1

My code behind file has its corresponding View Model as a public property for one of my Windows. I tried to data bind my ViewModel with the UI Elements in XAML but I always get error messages for that. However, when I try to create data bind using code, it works without any issues. I am really confused as to why this is happening and would like some guidance on what I am doing wrong.

Scenario 1 - Data binding fails when done in xaml

ProductInfoWindow.xaml:

<Window ...>
    <Grid Name="grdProd" DataContext="{Binding RelativeSource={RelativeSource Self}, Path=ViewModel}">
        <TextBox Name="txtName" Text="{Binding Product.Name}" />
    </Grid>
</Window>

ProductInfoWindow.xaml.cs:

public partial class ProductInfoWindow : Window
{
    public ProductInfoViewModel ViewModel { get; set; }

    public ProductInfo()
    {
        ViewModel = new ProductInfoViewModel(...);
    }
}

Error Messages in Output Window:

System.Windows.Data Error: 40 : BindingExpression path error: 'ViewModel' property not 
found on 'object' ''Grid' (Name='grdProd')'. BindingExpression:Path=ViewModel; 
DataItem='Grid' (Name='grdProd'); target element is 'Grid' (Name='grdProd'); target 
property is 'DataContext' (type 'Object')

Scenario 2 - Data binding works when done in code

ProductInfoWindow.xaml:

<Window ...>
    <Grid Name="grdProd">
        <TextBox Name="txtName" Text="{Binding Product.Name}" />
    </Grid>
</Window>

ProductInfoWindow.xaml.cs:

public partial class ProductInfoWindow : Window
{
    public ProductInfoViewModel ViewModel { get; set; }

    public ProductInfo()
    {
        ViewModel = new ProductInfoViewModel(...);
        grdProd.DataContext = ViewModel;
    }
}

Edit (09/08/2013)

ProductInfoViewModel.cs

public class ProductInfoViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, e);
    }

    private Product m_product;

    public Product Product
    {
        get
        {
            return m_product;
        }

        set
        {
            m_product = value;
            OnPropertyChanged(new PropertyChangedEventArgs("Product"));
        }
    }

    public ProductInfoViewModel(...)
    {
        Product = new Product(...);
    }
}
Parth Shah
  • 2,060
  • 1
  • 23
  • 34

1 Answers1

1

Your error message is telling you that the ViewModel property can't be found on the Grid 'grdProd', which is a fair point, because your Viewmodel is a public property defined on your ProductInfoWindow class.

Try setting the Datacontext at the Window level instead (adapting your example):

<Window DataContext="{Binding RelativeSource={RelativeSource Self}, Path=ViewModel}" ...>
    <Grid Name="grdProd"> 
        <TextBox Name="txtName" Text="{Binding Product.Name}" />
    </Grid>
</Window>
Chris
  • 8,268
  • 3
  • 33
  • 46
  • I am not getting any errors anymore. But none of the UI controls is displaying any information. I double checked that I followed your fix exactly as what you said. Your answer makes a lot of sense, so I am not sure why it is not happening. – Parth Shah Aug 08 '13 at 15:54
  • Where is your Viewmodel initialised? If initialisation occurs after the `Window` is created, the UI will not necessarily update, you'll need to implement `INotifyPropertyChanged` to inform your UI that changes to the bound objects are occuring. e.g. http://stackoverflow.com/questions/1315621/implementing-inotifypropertychanged-does-a-better-way-exist – Chris Aug 08 '13 at 16:39
  • Chris, I added my implementation of ProductInfoViewModel above in the "Edit" section. I tried debugging through the ViewModel last night and here is what I found. My PropertyChanged event handler is always null. This surprised me because I thought the xaml "Window DataContext=..." line would cause the PropertyChanged event handler to be initialized or something. – Parth Shah Aug 09 '13 at 02:29
  • If you're binding your window to a null `DataContext` which is being initialised later, your `Window` won't be aware that its `ViewModel` object has changed (and won't update the `DataContext`. You could implement `INotifyPropertyChanged` on the `Window`, but that's not a great fix. It would be better to instantiate your `ViewModel` before your view is created (you could do this before the call to `InitializeComponent();` in your `Window` constructor. – Chris Aug 09 '13 at 08:34