An Order form in UWP using Template 10 adds products to an order. The error is
Invalid binding path 'OrderViewModel.FindProduct_TextChanged' : Property 'OrderViewModel' can't be found on type 'ProductViewModel'
The relevant xaml snippet is
<Page.DataContext>
<ViewModels:MainPageViewModel x:Name="OrderViewModel" />
</Page.DataContext>
<GridView ItemsSource="{x:Bind OrderViewModel.Products, Mode=TwoWay}">
<GridView.ItemTemplate>
<DataTemplate x:DataType="ViewModels:ProductViewModel" >
<AutoSuggestBox
Name="ProductAutoSuggestBox"
TextMemberPath="{x:Bind ItemCode, Mode=TwoWay}"
TextChanged="{x:Bind OrderViewModel.FindProduct_TextChanged}">
</AutoSuggestBox>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
The relevant snippet from the OrderViewModel and the ProductViewModel
namespace ViewModels
{
public class OrderViewModel : ViewModelBase
{
public ObservableCollection<Product> Products { get; set; } = new ObservableCollection<Product>();
public void FindProduct_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
{ ... }
}
public class ProductViewModel : ViewModelBase
{
string _ItemCode = default(string);
public string ItemCode { get { return _ItemCode; } set { Set(ref _ItemCode, value); } }
public ProductViewModel()
{
}
}
}
How to I correctly reference FindProduct_TextChanged
on the OrderViewModel
from the DataTemplate for the GridView which references ProductViewModel
?
Voted up to @tao's comment. @Vague, I think you may misunderstand what x:DataType
is used for. You can refer to the "DataTemplate and x:DataType" part of Data binding in depth:
When using {x:Bind} in a data template, so that its bindings can be validated (and efficient code generated for them) at compile-time, the DataTemplate needs to declare the type of its data object using x:DataType.
For your scenario, from your code public ObservableCollection<Product> Products { get; set; } = new ObservableCollection<Product>();
, the type of your DataTemplate
's data object should be your Product
class, not your ProductViewModel
, and in the meanwhile, your FindProduct_TextChanged
event must be find in this Product
class, that means your code of FindProduct_TextChanged
should be placed in your Product
data model.
By the way, I think there is no need to use TwoWay
binding for ItemsSource
. For this scenario, the binding target is ItemsSource
of GridView
, the binding source is ObservableCollection<Product> Products
, I understand you want to update GridView
when your collection is updated, this is work is done with ObservableCollection. Besides, only the binding source here can be changed to notify the binding target, so OneWay
binding is enough. But it's not a big problem with your code.
So for your GridView
, it should be something like this:
<GridView ItemsSource="{x:Bind OrderViewModel.Products, Mode=OneWay}">
<GridView.ItemTemplate>
<DataTemplate x:DataType="Models:Product" >
<AutoSuggestBox
Name="ProductAutoSuggestBox"
TextMemberPath="{x:Bind ItemCode, Mode=TwoWay}"
TextChanged="{x:Bind FindProduct_TextChanged}">
</AutoSuggestBox>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>