// Intercept GetValue calls for certain ADO properties internal override object GetValue(object item, PropertyDescriptor pd, bool useFollowParent) { object value = GetRawValue(item, pd, useFollowParent); if (IsDataSetCollectionProperty(pd)) { // ADO returns a newly-created object (of type DataView or RelatedView) // for each call to the getter of a "DataSet collection property". // These objects are not referenced by any other ADO objects, // so it is up to the caller to keep them alive. But WPF tries // hard not to add strong references to these objects. There // are only three ways: // 1. Creating a BindingListCollectionView over the object // 2. Adding a ValueChanged listener for one of the object's properties // 3. Caching the object in the ValueTable // // Actually (3) no longer happens at all - it was causing a memory // leak of the entire DataSet. // // If the app never uses (1) or (2), there's nothing to keep the // object alive. There is a case where this actually // happens - the app uses bindings with indexers on the object, but // doesn't use any collection views or PropertyDescriptor-backed // properties. After a while, the object is GC'd, and the app // silently stops working. // // To fix this, we add a reference from a suitable ADO object to // the new DataView/RelatedView. This reference can't involve // any WPF objects - that would bring back the memory leak. // Instead, we use an ephemeral object created just for this purpose. // The ephemeral object subscribes to an event on the "suitable // ADO object", intentionally *not* using the WeakEvent pattern // so that the ADO object refers to the ephemeral object via the handler. // The ephemeral object also holds a strong reference to the new // DataView/RelatedView. Together, these references tie the // lifetime of the DataView/RelatedView to the lifetime of the // ADO object, as desired. if (pd.GetType() == s_DataTablePropertyDescriptorType) { // the "suitable ADO object" is the corresponding DataTable DataTable dataTable = (value as DataView)?.Table; if (dataTable != null) { new DataTableToDataViewLink(dataTable, value); } } else if (pd.GetType() == s_DataRelationPropertyDescriptorType) { // the "suitable ADO object" is the parent DataRowView DataRowView dataRowView = item as DataRowView; if (dataRowView != null) { new DataRowViewToRelatedViewLink(dataRowView, value); } } } return(value); }
private void contextMenuStripPropertyGrid_Opening(object sender, CancelEventArgs e) { GridItem gridItem = propertyGrid.SelectedGridItem; bool canReset = false; if (gridItem != null && gridItem.PropertyDescriptor != null) { PropertyDescriptor descriptor = gridItem.PropertyDescriptor; try { if (descriptor.GetType().Name == "MergePropertyDescriptor") { //hack for multiselection. FieldInfo field = descriptor.GetType().GetField( "descriptors", BindingFlags.Instance | BindingFlags.NonPublic); PropertyDescriptor[] childDescriptors = (PropertyDescriptor[])field.GetValue(descriptor); for (int n = 0; n < childDescriptors.Length; n++) { PropertyDescriptor childDescriptor = childDescriptors[n]; if (childDescriptor.CanResetValue(propertyGrid.SelectedObjects[n])) { canReset = true; break; } } } else { object component = null; GridItem parent = gridItem.Parent; if (parent.GridItemType == GridItemType.Category || parent.GridItemType == GridItemType.Root) { component = propertyGrid.SelectedObject; } else if (parent.GridItemType == GridItemType.Property) { component = parent.Value; } if (descriptor.CanResetValue(component)) { canReset = true; } } } catch { canReset = true; } } contextMenuStripPropertyGrid.Items[0].Enabled = canReset; }
private void contextMenuStripPropertyGrid_Opening(object sender, CancelEventArgs e) { GridItem selectedGridItem = this.jxPropertyGrid.SelectedGridItem; bool enabled = false; if (selectedGridItem != null && selectedGridItem.PropertyDescriptor != null) { PropertyDescriptor propertyDescriptor = selectedGridItem.PropertyDescriptor; try { if (propertyDescriptor.GetType().Name == "MergePropertyDescriptor") { FieldInfo field = propertyDescriptor.GetType().GetField("descriptors", BindingFlags.Instance | BindingFlags.NonPublic); PropertyDescriptor[] array = (PropertyDescriptor[])field.GetValue(propertyDescriptor); for (int i = 0; i < array.Length; i++) { PropertyDescriptor propertyDescriptor2 = array[i]; if (propertyDescriptor2.CanResetValue(this.jxPropertyGrid.SelectedObjects[i])) { enabled = true; break; } } } else { object component = null; GridItem parent = selectedGridItem.Parent; if (parent.GridItemType == GridItemType.Category || parent.GridItemType == GridItemType.Root) { component = this.jxPropertyGrid.SelectedObject; } else if (parent.GridItemType == GridItemType.Property) { component = parent.Value; } if (propertyDescriptor.CanResetValue(component)) { enabled = true; } } } catch { enabled = true; } } this.contextMenuStripPropertyGrid.Items[0].Enabled = enabled; while (this.contextMenuStripPropertyGrid.Items.Count > 1) { this.contextMenuStripPropertyGrid.Items.RemoveAt(this.contextMenuStripPropertyGrid.Items.Count - 1); } if (this.ContextMenuOpening != null) { this.ContextMenuOpening(this.contextMenuStripPropertyGrid); } }
static public string IdentifyAccessor(object accessor) { DependencyProperty dp = accessor as DependencyProperty; if (dp != null) { return(Format("{0}({1})", dp.GetType().Name, dp.Name)); } PropertyInfo pi = accessor as PropertyInfo;; if (pi != null) { return(Format("{0}({1})", pi.GetType().Name, pi.Name)); } PropertyDescriptor pd = accessor as PropertyDescriptor;; if (pd != null) { return(Format("{0}({1})", pd.GetType().Name, pd.Name)); } return(Identify(accessor)); }
private object GetRawValue(object item, PropertyDescriptor pd, bool useFollowParent) { if (useFollowParent && pd.GetType() == s_DataRelationPropertyDescriptorType) { // the DataRelation property returns a child view that doesn't // work in master/detail scenarios, when the primary key linking // the two tables changes. // ADO added a new method that returns a better child view, specifically // to fix this bug, but System.Data.DataRelationPropertyDescriptor.GetValue // still uses the old method: // // public override object GetValue(object component) { // DataRowView dataRowView = (DataRowView) component; // return dataRowView.CreateChildView(relation); // } // // so we intercept the GetValue call and use the new method. // (The value of the 'relation' member isn't publicly visible, // but its name is. That's enough to call the new method.) DataRowView dataRowView = (DataRowView)item; return(dataRowView.CreateChildView(pd.Name, followParent: true)); } // otherwise, call GetValue the normal way return(pd.GetValue(item)); }
protected void SerializeProperty(IDesignerSerializationManager manager, CodeStatementCollection statements, object value, PropertyDescriptor propertyToSerialize) { if (propertyToSerialize == null) { throw new ArgumentNullException("propertyToSerialize"); } if (value == null) { throw new ArgumentNullException("value"); } if (statements == null) { throw new ArgumentNullException("statements"); } if (manager == null) { throw new ArgumentNullException("manager"); } MemberCodeDomSerializer serializer = manager.GetSerializer(propertyToSerialize.GetType(), typeof(MemberCodeDomSerializer)) as MemberCodeDomSerializer; if (serializer != null && serializer.ShouldSerialize(manager, value, propertyToSerialize)) { serializer.Serialize(manager, value, propertyToSerialize, statements); } }
// XLinq exposes several properties on XElement that create new objects // every time the getter is called. We have to live with this, since // the property descriptors carry state that depends on components later // in the path (e.g. when path=Attribute[FirstName], the value returned by // the Attribute PD can only be used to look up "FirstName"). But we need // to be aware of it in certain circumstances - e.g. when checking for // event leapfrogging. internal override bool IsXLinqNonIdempotentProperty(PropertyDescriptor pd) { Type pdType = pd.GetType(); return((pdType == s_XElementAttributePropertyDescriptorType) || (pdType == s_XElementElementPropertyDescriptorType)); }
// XLinq exposes two synthetic properties - Elements and Descendants - // on XElement that return IEnumerable<XElement>. We handle these specially // to work around problems involving identity and change notifications internal override bool IsXLinqCollectionProperty(PropertyDescriptor pd) { Type pdType = pd.GetType(); return((pdType == s_XElementElementsPropertyDescriptorType) || (pdType == s_XElementDescendantsPropertyDescriptorType)); }
/// <summary> /// /// </summary> /// <param name="property"></param> /// <returns></returns> public static string GetFieldName(PropertyDescriptor property) { DbFieldAttribute attribute = property.Attributes[_TypeOf_Field] as DbFieldAttribute; if (attribute != null) { return(attribute.FieldName); } throw FieldNotExists(string.Format("for property: {0}", property.Name), property.GetType()); }
/// <summary> /// Returns the PropertyDescriptorCollection for the relation or nested collection. /// </summary> /// <param name="pd"></param> /// <returns></returns> public static DataRelation GetDataRelation(PropertyDescriptor pd) { if (!BrowserInteropHelper.IsBrowserHosted) { if (pd != null && pd.GetType().FullName == "System.Data.DataRelationPropertyDescriptor") { var t = pd.GetType(); var pi = t.GetProperty("Relation", BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.IgnoreReturn | BindingFlags.Instance | BindingFlags.NonPublic); if (pi != null) { var mInfo = pi.GetGetMethod(true); if (mInfo != null) { var dr = mInfo.Invoke(pd, new object[0]) as DataRelation; return(dr); } } } } return(null); }
public static string GetCaption(PropertyDescriptor descriptor) { try { PropertyInfo property = descriptor.GetType().GetProperty("Column", BindingFlags.Instance | BindingFlags.NonPublic); if ((object)property == null) { return((string)null); } return((property.GetValue((object)descriptor, (object[])null) as DataColumn).Caption); } catch { return((string)null); } }
private static PropertyDescriptorCollection WrapProperties(PropertyDescriptorCollection oldProps) { PropertyDescriptor[] newProps = new PropertyDescriptor[oldProps.Count]; int index = 0; bool changed = false; // HACK: how to identify reflection, given that the class is internal... Type wrapMe = Assembly.GetAssembly(typeof(PropertyDescriptor)).GetType("System.ComponentModel.ReflectPropertyDescriptor"); foreach (PropertyDescriptor oldProp in oldProps) { PropertyDescriptor pd = oldProp; // if it looks like reflection, try to create a bespoke descriptor if (ReferenceEquals(wrapMe, pd.GetType()) && TryCreatePropertyDescriptor(ref pd)) { changed = true; } newProps[index++] = pd; } return(changed ? new PropertyDescriptorCollection(newProps, true) : oldProps); }
// ADO DataSet exposes some properties that cause problems involving // identity and change notifications. We handle these specially. internal override bool IsDataSetCollectionProperty(PropertyDescriptor pd) { if (s_DataTablePropertyDescriptorType == null) { // lazy load the types for the offending PD's. They're internal, so // we get them indirectly. DataSet dataset = new DataSet(); dataset.Locale = System.Globalization.CultureInfo.InvariantCulture; DataTable table1 = new DataTable("Table1"); table1.Locale = System.Globalization.CultureInfo.InvariantCulture; table1.Columns.Add("ID", typeof(int)); dataset.Tables.Add(table1); DataTable table2 = new DataTable("Table2"); table2.Locale = System.Globalization.CultureInfo.InvariantCulture; table2.Columns.Add("ID", typeof(int)); dataset.Tables.Add(table2); dataset.Relations.Add(new DataRelation("IDRelation", table1.Columns["ID"], table2.Columns["ID"])); System.Collections.IList list = ((IListSource)dataset).GetList(); PropertyDescriptorCollection pdc = TypeDescriptor.GetProperties(list[0]); s_DataTablePropertyDescriptorType = pdc["Table1"].GetType(); pdc = ((ITypedList)table1.DefaultView).GetItemProperties(null); s_DataRelationPropertyDescriptorType = pdc["IDRelation"].GetType(); } Type pdType = pd.GetType(); return((pdType == s_DataTablePropertyDescriptorType) || (pdType == s_DataRelationPropertyDescriptorType)); }
private static PropertyInfo GetPropertyInfo(PropertyDescriptor prop, string name) => prop.GetType().GetProperty(name, BindingFlags.Instance | BindingFlags.NonPublic);
private static bool IsReflected(PropertyDescriptor descriptor) { return((descriptor != null) && (descriptor.GetType() == s_reflectPropertyDescriptorType)); }