I have a SL5 project where I am trying to data bind a collection to a ItemsControl, I keep getting the error:
BindingExpression path error: 'ItemName' property not found on 'EventViewer.Data.ViewModels.ProductListModel' 'EventViewer.Data.ViewModels.ProductListModel' (HashCode=7414170). BindingExpression: Path='ItemName' DataItem='EventViewer.Data.ViewModels.ProductListModel' (HashCode=7414170); target element is 'System.Windows.Controls.TextBlock' (Name=''); target property is 'Text' (type 'System.String').. BindingExpression path error: 'Price' property not found on 'EventViewer.Data.ViewModels.ProductListModel' 'EventViewer.Data.ViewModels.ProductListModel' (HashCode=7414170). BindingExpression: Path='Price' DataItem='EventViewer.Data.ViewModels.ProductListModel' (HashCode=7414170); target element is 'System.Windows.Controls.TextBlock' (Name=''); target property is 'Text' (type 'System.String').. BindingExpression path error: 'Description' property not found on 'EventViewer.Data.ViewModels.ProductListModel' 'EventViewer.Data.ViewModels.ProductListModel' (HashCode=7414170). BindingExpression: Path='Description' DataItem='EventViewer.Data.ViewModels.ProductListModel' (HashCode=7414170); target element is 'System.Windows.Controls.TextBlock' (Name=''); target property is 'Text' (type 'System.String').. I have these properties in the ProductQtyItem and the databinding appears to be setup correctly. Here is what I have:
The XAML:
<sdk:ChildWindow xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" xmlns:EventViewer="clr-namespace:EventViewer" xmlns:ViewModels="clr-namespace:EventViewer.Data.ViewModels" xmlns:converters="clr-namespace:EventViewer.Converters" x:Class="EventViewer.PurchaseWindow" Title="Purchase" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="539" Height="550"> <sdk:ChildWindow.Resources> <converters:BooleanVisibilityConverter x:Key="BooleanVisibilityConverter"/> <converters:NumericCurrencyConverter x:Key="NumericCurrencyConverter"/> <ControlTemplate x:Key="ProductItemTemplate" TargetType="ItemsControl"> <Grid Margin="3"> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <TextBlock Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" VerticalAlignment="Center" Style="{StaticResource ProductNameTextBlockStyle}" Text="{Binding ItemName, Mode=OneWay}"/> <TextBlock Grid.Column="0" Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Center" Style="{StaticResource ProductPriceTextBlockStyle}" Text="{Binding Price, Converter={StaticResource NumericCurrencyConverter}, Mode=OneWay}" /> <TextBlock Grid.Column="1" Grid.Row="1" HorizontalAlignment="Right" VerticalAlignment="Center" TextWrapping="Wrap" Text="{Binding Description, Mode=OneWay}"/> </Grid> </ControlTemplate> </sdk:ChildWindow.Resources> <Grid x:Name="LayoutRoot"> <Grid.DataContext> <ViewModels:ProductListModel/> </Grid.DataContext> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <Viewbox Stretch="Uniform" StretchDirection="DownOnly" HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" Height="100" DataContext="{Binding ImageData}"> <Image Source="{Binding ImagePath, Mode=OneWay}" ImageOpened="Image_ImageOpened"/> </Viewbox> <ItemsControl HorizontalAlignment="Left" Margin="0,105,0,0" VerticalAlignment="Top" Width="521" Height="377" Template="{StaticResource ProductItemTemplate}" ItemsSource="{Binding ProductQtyItems}"/> <Button x:Name="OKButton" Content="OK" Click="OKButton_Click" Width="75" Height="23" HorizontalAlignment="Right" Grid.Row="1" /> </Grid> </sdk:ChildWindow> The code that is to follow is how I wire up a ProductListModel to the LayoutRoot.DataContext of the above XAML code. So, if I understand things correctly, the binding for the ItemsControl will bind to the List ProductQtyItems of ProductListModel. So, won't the templates have the datasource set to ProductQtyItem? What am I missing?
Here is the rest of the code:
And this is the code that populates the data binding:
public static void Display(FrameworkElement parent, ImageData imageData) { var purchaseWindow = new PurchaseWindow(); var productQtyItems = new List<ProductQtyItem>(); foreach (var p in SystemSettings.GetInstance().ProductList.Collection) { int qty = 0; imageData.ProductListItemQty.TryGetValue(p.Id, out qty); productQtyItems.Add(ProductQtyItem.Create(p, qty)); } purchaseWindow.LayoutRoot.DataContext = new ProductListModel { ImageData = imageData, ProductQtyItems = productQtyItems }; purchaseWindow.Show(); } Here is the Model that is being set to the LayoutRoot.Datacontext:
public class ProductListModel : PropertyChangedBase { private List<ProductQtyItem> _productQtyItems; private ImageData _imageData; public List<ProductQtyItem> ProductQtyItems { get { return _productQtyItems; } set { _productQtyItems = value; } } public ImageData ImageData { get { return _imageData; } set { _imageData = value; } } } And finally the ProductQtyItem:
public class ProductQtyItem : PropertyChangedBase { public static ProductQtyItem Create(ProductItem productItem, int qty) { return new ProductQtyItem { _productItem = productItem, _qty = qty, }; } private ProductItem _productItem; private int _qty; public int Id { get { return _productItem.Id; } } public int SortOrder { get { return _productItem.SortOrder; } } public string ItemName { get { return _productItem.ItemName; } } public string Description { get { return _productItem.Description; } } public double Price { get { return _productItem.Price; } } public bool IsQtyEnabled { get { return _productItem.IsQtyEnabled; } } public int Qty { get { return _qty; } set { if (value != _qty) { _qty = value; NotifyPropertyChanged("Qty"); } } } public override bool Equals(object obj) { var other = obj as ProductQtyItem; if (other == null) return false; return Id == other.Id; } public override int GetHashCode() { return Id; } }