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;
}
}