One possible solution is instead of using a simple collection as the inner object, create a class derived from a collection and implement ICustomTypeDescriptor
on it. In the interface implementation, iterate over the elements of the collection and populate your property descriptor collection accordingly. Once you do that, you should be able to bind to those properties from XAML.
Example - a data object based on a dictionary, which you can bind against its key names (I compressed to a single line all trivial method implementations):
class DictionaryDataObject : Dictionary<string, object>, ICustomTypeDescriptor
{
#region ICustomTypeDescriptor Members
public AttributeCollection GetAttributes() { return AttributeCollection.Empty; }
public string GetClassName() { return "DictionaryDataObject"; }
public string GetComponentName() { return null; }
public TypeConverter GetConverter() { return null; }
public EventDescriptor GetDefaultEvent() { return null; }
public PropertyDescriptor GetDefaultProperty() { return null; }
public object GetEditor(Type editorBaseType) { return null; }
public EventDescriptorCollection GetEvents(Attribute[] attributes) { return EventDescriptorCollection.Empty; }
public EventDescriptorCollection GetEvents() { return EventDescriptorCollection.Empty; }
public PropertyDescriptorCollection GetProperties() { return GetProperties(null); }
public object GetPropertyOwner(PropertyDescriptor pd) { return this; }
public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
var pds =
this.Keys
.Select(x => new DictionaryPropertyDescriptor(x))
.ToArray();
return new PropertyDescriptorCollection(pds);
}
#endregion
}
class DictionaryPropertyDescriptor : PropertyDescriptor
{
public DictionaryPropertyDescriptor(string name) : base(name, null) { }
public override bool CanResetValue(object component) { return false; }
public override Type ComponentType { get { return null; } }
public override bool IsReadOnly { get { return false; } }
public override Type PropertyType { get { return typeof(object); } }
public override void ResetValue(object component) { }
public override bool ShouldSerializeValue(object component) { return false; }
public override object GetValue(object component)
{
var dic = component as DictionaryDataObject;
if (dic == null) return null;
return dic[Name];
}
public override void SetValue(object component, object value)
{
var dic = component as DictionaryDataObject;
if (dic == null) return;
dic[Name] = value;
}
}
Sample object setup from code behind:
DictionaryDataObject ddo = new DictionaryDataObject();
public Window4()
{
ddo["propa"] = 1;
ddo["propb"] = "foo";
ddo["propc"] = "bar";
ddo["propd"] = 4.5;
InitializeComponent();
DataContext = ddo;
}
XAML usage:
<Window.Resources>
<DataTemplate x:Key="template">
<WrapPanel>
<TextBlock Text="{Binding propa}" Margin="5"/>
<TextBlock Text="{Binding propb}" Margin="5"/>
<TextBlock Text="{Binding propc}" Margin="5"/>
<TextBlock Text="{Binding propd}" Margin="5"/>
</WrapPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<ContentControl Content="{Binding}" ContentTemplate="{StaticResource template}"/>
</Grid>
If you want to adapt this solution to a list instead of a dictionary, you must set each property name based on some property of the list element.