In WPF4.0, I have a class that contains other class types as properties (combining multiple data types for display). Something like:
public partial class Owner
{
public string OwnerName { get; set; }
public int OwnerId { get; set; }
}
partial class ForDisplay
{
public Owner OwnerData { get; set; }
public int Credit { get; set; }
}
In my window, I have an ItemsControl with the following (clipped for clarity):
<ItemsControl ItemsSource={Binding}>
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:MyDisplayControl
OwnerName={Binding OwnerData.OwnerName}
Credit={Binding Credit} />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I then get a collection of display information from the data layer, and set the DataContext
of the ItemsControl
to this collection. The "Credit" property gets displayed correctly, but the OwnerName property does not. Instead, I get a binding error:
Error 40: BindingExpression path error: 'OwnerName' property not found on 'object' ''ForDisplay' (HashCode=449124874)'. BindingExpression:Path=OwnerName; DataItem='ForDisplay' (HashCode=449124874); target element is 'TextBlock' (Name=txtOwnerName'); target property is 'Text' (type 'String')
I don't understand why this is attempting to look for the OwnerName property in the ForDisplay class, rather than in the Owner class from the ForDisplay OwnerData property.
Edit
It appears that it has something to do with using the custom control. If I bind the same properties to a TextBlock
, they work correctly.
<ItemsControl ItemsSource={Binding}>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<local:MyDisplayControl
OwnerName={Binding OwnerData.OwnerName}
Credit={Binding Credit} />
<TextBlock Text="{Binding OwnerData.OwnerName}" />
<TextBlock Text="{Binding Credit}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
The ItemsPanelTemplate specifies the panel that is used for the layout of items. GroupStyle has a Panel property that is of type ItemsPanelTemplate. ItemsControl types have an ItemsPanel property that is of type ItemsPanelTemplate. Each ItemsControl type has a default ItemsPanelTemplate.
Use either the Items or the ItemsSource property to specify the collection to use to generate the content of your ItemsControl. You can set the ItemsSource property to any type that implements IEnumerable. ItemsSource is typically used to display a data collection or to bind an ItemsControl to a collection object.
You use the ItemTemplate to specify the visualization of the data objects. If your ItemsControl is bound to a collection object and you do not provide specific display instructions using a DataTemplate, the resulting UI of each item is a string representation of each object in the underlying collection.
ItemsSource can be data bound to any sequence that implements the IEnumerable interface, although the type of collection used does determine the way in which the control is updated when items are added to or removed. When ItemsSource is set, the Items property cannot be used to control the displayed values.
Are you sure the code you posted here IS the code you use in your solution? Because, this code works for me :
XAML
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding OwnerData.OwnerName}"></TextBlock>
<TextBlock Text="{Binding Credit}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Window's Loaded Event
ObservableCollection<ForDisplay> items = new ObservableCollection<ForDisplay>();
for (int i = 0; i < 10; i++)
{
items.Add(new ForDisplay() { OwnerData = new Owner() { OwnerId = i + 1, OwnerName = String.Format("Owner #{0}", i + 1) }, Credit = i + 1 });
}
DataContext = items;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With