Search code examples
c#wpfbindingitemtemplateitemssource

WPF binding in ItemTemplate works but produces error messages


I am using Mahapps.Metro.Controls.DropDownButton in a UserControl in my project, which I populate using data binding. In order to know which item gets selected, I apply an item template in which I specify the item click handler. The relevant XAML is

<Controls:DropDownButton
    x:Name="selector"
    VerticalContentAlignment="Center"
    Content=" "
    Background="Transparent"
    BorderThickness="0"
    ItemsSource="{Binding Catalogues}"
>
   <Controls:DropDownButton.ItemTemplate>
      <DataTemplate>
         <TextBlock Text="{Binding Id}" MouseDown="HandleDropDownItemMouseDown" />
      </DataTemplate>
   </Controls:DropDownButton.ItemTemplate>
</Controls:DropDownButton>

The DataContext is a custom view model set in the constructor in the code-behind for the user control:

public CatalogueEditor()
{
        InitializeComponent();

        this.viewModel = new CatalogueEditorViewModel();
        this.DataContext = this.viewModel;
}

The Catalogues property in the view model is a custom KeyedCollection<string, Catalogue> that implements INotifyCollectionChanged. This contains elements that are similar custom KeyedCollection objects implementing INotifyCollectionChanged, but with item type Question, which is no longer a collection. Catalogue objects have a read-only property Id, to which I bind the TextBlock in the item template.

The binding seems to work all right and the DropDownButton gets populated with the Id labels of the Catalogue objects in the Catalogues collection, yet I get an output informing me of a binding error:

System.Windows.Data Error: 40 : BindingExpression path error: 'Id' property not found on 'object' ''String' (HashCode=-842352768)'. BindingExpression:Path=Id; DataItem='String' (HashCode=-842352768); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')

This tells me that at some point the DataContext of the TextBlock in the item template is perceived as a String, though I intend it to be a Catalogue as an item in the collection bound to the ItemsSource. It is not only the correct operation that corroborates this notion but also my HandleDropDownItemMouseDown event handler:

void HandleDropDownItemMouseDown(object sender, MouseButtonEventArgs e)
{
        if (e.ChangedButton == MouseButton.Left && selector.IsExpanded) {
            Catalogue catalogue = ((TextBlock)e.Source).DataContext as Catalogue;

            if (catalogue != null) {
                viewModel.Select(catalogue);
            }
        }
}

Placing a breakpoint here I can see that the DataContext of the TextBlock is indeed a Catalogue and the code works as intended.

Why does this apparent error message occur? Shall I worry about it, does it signify that I made some insidious mistake in my code, or shall I be content that the code works? My apologies if this is an irrelevant or stupid question, but I am just learning WPF and I find it quite challenging, so I try to understand what happens around me even if my code happens to work. Your insights are much appreciated.


Solution

  • The offending line is Content=" ". You are setting content of a control to " " string, to which control tries to apply your template. As string class has no Id property, it results in a binding error.