I'm looking to create something akin to one of the features of VS or Blend whereby when one selects multiple objects, the property grid shows the value for any property that is shared by all objects and shows nothing for properties that differ between the objects.
I've managed to implement this behaviour for CLR properties using a dynamic object:
_knownProperties
is just a list of properties which have previously been requested_collection
is an IEnumerable instance
public override bool TryGetMember( GetMemberBinder binder, out object result ) {
Debug.WriteLine( "Getting " + binder.Name + "..." );
if (!_knownProperties.Contains( binder.Name ))
_knownProperties.Add( binder.Name );
IEnumerator it = _collection.GetEnumerator();
if (!it.MoveNext()) {
result = null;
Debug.WriteLine( "No elements in collection" );
return true;
}
Type t = it.Current.GetType();
PropertyInfo pinf = t.GetProperty( binder.Name );
if (pinf == null) {
result = null;
Debug.WriteLine( "Property doesn't exist." );
return true;
}
result = pinf.GetValue( it.Current, null );
if (result == null) {
Debug.WriteLine( "Null result" );
return true;
}
while (it.MoveNext())
if (!result.Equals( it.Current.GetType().GetProperty( binder.Name ).GetValue( it.Current, null ) )) {
result = null;
Debug.WriteLine( "Null result" );
return true;
}
Debug.WriteLine( "Result: " + result.ToString() );
return true;
}
I'm accessing these properties via WPF Bindings.
Can anyone think of a way to implement this for DependencyProperties? If I attempt to bind to an attached property on the object, I get an ArgumentNullException
in the property system (where the object that is null can't possibly be null according to the source I have)
{Binding Selection.SomeClrProperty,...}
works fine (Selection
is one of the dynamic objects,SomeClrProperty
is a property on every element of the collection.{Binding Selection.(SomeClass.SomeAttachedProperty),...}
Fires an error in the property system
The Exception:
System.ArgumentNullException was unhandled
Message=Key cannot be null.
Parameter name: key
Source=System
ParamName=key
StackTrace:
at System.Collections.Specialized.HybridDictionary.get_Item(Object key)
at System.ComponentModel.PropertyChangedEventManager.PrivateAddListener(INotifyPropertyChanged source, IWeakEventListener listener, String propertyName)
at System.ComponentModel.PropertyChangedEventManager.AddListener(INotifyPropertyChanged source, IWeakEventListener listener, String propertyName)
at MS.Internal.Data.PropertyPathWorker.ReplaceItem(Int32 k, Object newO, Object parent)
at MS.Internal.Data.PropertyPathWorker.UpdateSourceValueState(Int32 k, ICollectionView collectionView, Object newValue, Boolean isASubPropertyChange)
at MS.Internal.Data.ClrBindingWorker.AttachDataItem()
at System.Windows.Data.BindingExpression.Activate(Object item)
...