private void ExtractTemplateValuesRecursive(ArrayList subBuilders, OrderedDictionary table, Control container) { foreach (object subBuilderObject in subBuilders) { ControlBuilder subBuilderControlBuilder = subBuilderObject as ControlBuilder; if (subBuilderControlBuilder != null) { ICollection entries; // filter out device filtered bound entries that don't apply to this device if (!subBuilderControlBuilder.HasFilteredBoundEntries) { entries = subBuilderControlBuilder.BoundPropertyEntries; } else { Debug.Assert(subBuilderControlBuilder.ServiceProvider == null); Debug.Assert(subBuilderControlBuilder.TemplateControl != null, "TemplateControl should not be null in no-compile pages. We need it for the FilterResolutionService."); ServiceContainer serviceContainer = new ServiceContainer(); serviceContainer.AddService(typeof(IFilterResolutionService), subBuilderControlBuilder.TemplateControl); try { subBuilderControlBuilder.SetServiceProvider(serviceContainer); entries = subBuilderControlBuilder.GetFilteredPropertyEntrySet(subBuilderControlBuilder.BoundPropertyEntries); } finally { subBuilderControlBuilder.SetServiceProvider(null); } } string previousControlName = null; bool newControl = true; Control control = null; foreach (BoundPropertyEntry entry in entries) { // Skip all entries that are not two-way if (!entry.TwoWayBound) { continue; } // Reset the "previous" Property Entry if we're not looking at the same control. // If we don't do this, Two controls that have conditionals on the same named property will have // their conditionals incorrectly merged. if (String.Compare(previousControlName, entry.ControlID, StringComparison.Ordinal) != 0) { newControl = true; } else { newControl = false; } previousControlName = entry.ControlID; if (newControl) { control = container.FindControl(entry.ControlID); if (control == null || !entry.ControlType.IsInstanceOfType(control)) { Debug.Assert(false, "BoundPropertyEntry is of wrong control type or couldn't be found. Expected " + entry.ControlType.Name); continue; } } string propertyName; // map the property in case it's a complex property object targetObject = PropertyMapper.LocatePropertyObject(control, entry.Name, out propertyName, InDesigner); // FastPropertyAccessor uses ReflectEmit for lightning speed table[entry.FieldName] = FastPropertyAccessor.GetProperty(targetObject, propertyName, InDesigner); } ExtractTemplateValuesRecursive(subBuilderControlBuilder.SubBuilders, table, container); } } }
/* * Set all the properties we have on the passed in object * This is not called when generating code for compiling... it is * used in design-mode, and at runtime when the user calls Page.ParseControl */ internal void SetProperties(object obj) { Debug.Assert(_fInDesigner, "Expected to be running in design mode."); object[] parameters = new object[1]; IAttributeAccessor attributeAccessor = null; DataBindingCollection dataBindings = null; if (_fDataBound && (_entries.Count != 0)) { Debug.Assert(obj is Control, "SetProperties on databindings PropertySetter should only be called for controls."); dataBindings = ((IDataBindingsAccessor)obj).DataBindings; } // Get the supported attribute interfaces if (_fSupportsAttributes) { attributeAccessor = (IAttributeAccessor)obj; } IEnumerator en = _entries.GetEnumerator(); while (en.MoveNext()) { PropertySetterEntry entry = (PropertySetterEntry)en.Current; if (entry._propType == null) { if (entry._fItemProp) { try { object objValue = entry._builder.BuildObject(); parameters[0] = objValue; MethodInfo methodInfo = _objType.GetMethod("Add", BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static, null /*binder*/, new Type[] { objValue.GetType() }, null /*modifiers*/); Util.InvokeMethod(methodInfo, obj, parameters); } catch (Exception) { throw new HttpException( HttpRuntime.FormatResourceString(SR.Cannot_add_value_not_collection, entry._value)); } } else { // If there is no property, use SetAttribute if (attributeAccessor != null) { attributeAccessor.SetAttribute(entry._name, entry._value); } } } else { // Use the propinfo to set the prop // Use either _propValue or _builder, whichever is set if (entry._propValue != null) { try { PropertyMapper.SetMappedPropertyValue(obj, entry._name, entry._propValue); } catch (Exception e) { throw new HttpException( HttpRuntime.FormatResourceString(SR.Cannot_set_property, entry._value, entry._name), e); } } else if (entry._builder != null) { if (entry._fReadOnlyProp) { // a complex property is allowed to be readonly try { object objValue; // Get the property since its readonly MethodInfo methodInfo = entry._propInfo.GetGetMethod(); objValue = Util.InvokeMethod(methodInfo, obj, null); // now we need to initialize this property entry._builder.InitObject(objValue); } catch (Exception e) { throw new HttpException( HttpRuntime.FormatResourceString(SR.Cannot_init, entry._name), e); } } else { try { object objValue = entry._builder.BuildObject(); parameters[0] = objValue; // Set the property MethodInfo methodInfo = entry._propInfo.GetSetMethod(); Util.InvokeMethod(methodInfo, obj, parameters); } catch (Exception e) { throw new HttpException( HttpRuntime.FormatResourceString(SR.Cannot_set_property, entry._value, entry._name), e); } } } else if (dataBindings != null) { DataBinding binding = new DataBinding(entry._name, entry._propType, entry._value.Trim()); dataBindings.Add(binding); } else { Debug.Assert(false, "'" + entry._value + "' failed to be set on property '" + entry._name + "'."); } } } }
private void AddPropertyInternal(string name, string value, ControlBuilder builder, bool fItemProp) { PropertySetterEntry entry = new PropertySetterEntry(); bool fTemplate = false; string nameForCodeGen = null; entry._value = value; entry._builder = builder; entry._fItemProp = fItemProp; MemberInfo memberInfo = null; PropertyInfo propInfo = null; FieldInfo fieldInfo = null; // Is the property a template? if (builder != null && builder is TemplateBuilder) { fTemplate = true; } if (_objType != null && name != null) // attempt to locate a public property or field // of given name on this type of object { memberInfo = PropertyMapper.GetMemberInfo(_objType, name, out nameForCodeGen); } if (memberInfo != null) // memberInfo may be a PropertyInfo or FieldInfo { if (memberInfo is PropertyInfo) // public property { propInfo = (PropertyInfo)memberInfo; entry._propType = propInfo.PropertyType; if (propInfo.GetSetMethod() == null) // property is readonly { if (builder == null && !_fSupportsAttributes) // only complex property is allowed to be readonly { throw new HttpException( HttpRuntime.FormatResourceString(SR.Property_readonly, name)); } if (builder != null) // complex property is allowed to be readonly // set a flag to note that property is readonly { entry._fReadOnlyProp = true; } else if (_fSupportsAttributes) // allow attribute to be set via SetAttribute { entry._propType = null; entry._name = name; } } } else // public field { fieldInfo = (FieldInfo)memberInfo; entry._propType = fieldInfo.FieldType; } if (entry._propType != null) { entry._propInfo = propInfo; entry._fieldInfo = fieldInfo; entry._name = nameForCodeGen; // If it's a databound prop, we don't want to mess with the value, // since it's a piece of code. if (!_fDataBound) { // check that the property is persistable, i.e., it makes sense to have it in // the aspx template if (_checkPersistable && nameForCodeGen != null) { PropertyDescriptor propDesc = _descriptors[nameForCodeGen]; if (propDesc != null) { if (propDesc.Attributes.Contains(DesignerSerializationVisibilityAttribute.Hidden)) { throw new HttpException(HttpRuntime.FormatResourceString(SR.Property_Not_Persistable, name)); } } } else { if (_isHtmlControl) { PropertyDescriptor propDesc = _descriptors[nameForCodeGen]; if (propDesc != null) { if (propDesc.Attributes.Contains(HtmlControlPersistableAttribute.No)) { throw new HttpException(HttpRuntime.FormatResourceString(SR.Property_Not_Persistable, name)); } } } } entry._propValue = PropertyConverter.ObjectFromString(entry._propType, memberInfo, entry._value); // use actual property value to get the proper case-sensitive name for enum types if (entry._propType.IsEnum) { if (entry._propValue == null) { throw new HttpException( HttpRuntime.FormatResourceString(SR.Invalid_enum_value, entry._value, name, entry._propType.FullName)); } entry._value = Enum.Format(entry._propType, entry._propValue, "G"); } else if (entry._propType == typeof(Boolean)) { // get the proper case-sensitive value for boolean if (entry._value != null && entry._value.Length > 0) { entry._value = entry._value.ToLower(CultureInfo.InvariantCulture); } else { entry._propValue = true; } } if (fTemplate) { // Check if the property has a TemplateContainerAttribute, and if // it does, get the type out of it. TemplateContainerAttribute templateAttrib = (TemplateContainerAttribute)Attribute.GetCustomAttribute(propInfo, typeof(TemplateContainerAttribute), false); if (templateAttrib != null) { if (!typeof(INamingContainer).IsAssignableFrom(templateAttrib.ContainerType)) { throw new HttpException(HttpRuntime.FormatResourceString( SR.Invalid_template_container, name, templateAttrib.ContainerType.FullName)); } builder._ctrlType = templateAttrib.ContainerType; } } } } } else if (fItemProp) { } else // could not locate a public property or field // determine if there is an event of this name. // do not look for events when running in designer { if (!_fInDesigner && _objType != null && name.Length >= 2 && string.Compare(name.Substring(0, 2), "on", true, CultureInfo.InvariantCulture) == 0) { string eventName = name.Substring(2); if (_eventDescs == null) { _eventDescs = TypeDescriptor.GetEvents(_objType); } EventDescriptor eventFound = _eventDescs.Find(eventName, true); if (eventFound != null) // an Add method has been located { PropertySetterEventEntry eventEntry = new PropertySetterEventEntry(); eventEntry._eventName = eventFound.Name; eventEntry._handlerType = eventFound.EventType; if (value == null || value.Length == 0) { throw new HttpException( HttpRuntime.FormatResourceString(SR.Event_handler_cant_be_empty, name)); } eventEntry._handlerMethodName = value; if (_events == null) { _events = new ArrayList(3); } // add to the list of events _events.Add(eventEntry); return; } } // If attributes are not supported, or the property is a template or a // complex property (which cannot be set through SetAttribute), fail. if (!_fInDesigner && (!_fSupportsAttributes || builder != null)) { if (_objType != null) { throw new HttpException( HttpRuntime.FormatResourceString(SR.Type_doesnt_have_property, _objType.FullName, name)); } if (String.Compare(name, "name", true, CultureInfo.InvariantCulture) != 0) { throw new HttpException(HttpRuntime.FormatResourceString(SR.Templates_cannot_have_properties)); } else { return; } } // use the original property name for generic SetAttribute entry._name = name; } if (_entries == null) { _entries = new ArrayList(3); } // add entry to the list _entries.Add(entry); }
private void ApplyComplexProperties(Control control) { ICollection entries = GetFilteredPropertyEntrySet(_skinBuilder.ComplexPropertyEntries); foreach (ComplexPropertyEntry entry in entries) { ControlBuilder builder = entry.Builder; if (builder != null) { string propertyName = entry.Name; if (entry.ReadOnly) { object objectValue = FastPropertyAccessor.GetProperty(control, propertyName, InDesigner); if (objectValue == null) { continue; } entry.Builder.SetServiceProvider(ServiceProvider); try { entry.Builder.InitObject(objectValue); } finally { entry.Builder.SetServiceProvider(null); } } else { object childObj; string actualPropName; object value = entry.Builder.BuildObject(true); // Make the UrlProperty based on theme path for control themes(Must be a string) PropertyDescriptor desc = PropertyMapper.GetMappedPropertyDescriptor(control, PropertyMapper.MapNameToPropertyName(propertyName), out childObj, out actualPropName, InDesigner); if (desc != null) { string str = value as string; if (value != null && desc.Attributes[typeof(UrlPropertyAttribute)] != null && UrlPath.IsRelativeUrl(str)) { value = _themePath + str; } } FastPropertyAccessor.SetProperty(childObj, propertyName, value, InDesigner); } } } }