Just hit a very odd issue with databinding which I cannot seem to get to the bottom of:
Scenario
An MVVM View model data bound to a parent form with two properties
public RelayCommand ClearFilteredCategories { get; private set; }
/// <summary>
/// The <see cref="ClearFilterText" /> property's name.
/// </summary>
public const string ClearFilterTextPropertyName = "ClearFilterText";
private string _clearFilterText = "Clear Filter";
/// <summary>
/// Sets and gets the ClearFilterText property.
/// Changes to that property's value raise the PropertyChanged event.
/// </summary>
public string ClearFilterText
{
get
{
return _clearFilterText;
}
set
{
if (_clearFilterText == value)
{
return;
}
_clearFilterText = value;
RaisePropertyChanged(ClearFilterTextPropertyName);
}
}
Then I have a User control with Two dependency Properties, thus:
public partial class ClearFilterButton : UserControl
{
public ClearFilterButton()
{
// Required to initialize variables
InitializeComponent();
}
public string ClearFilterString
{
get { return (string)GetValue(ClearFilterStringProperty); }
set { SetValue(ClearFilterStringProperty, value); }
}
public RelayCommand ClearFilterAction
{
get { return (RelayCommand)GetValue(ClearFilterActionProperty); }
set { SetValue(ClearFilterActionProperty, value); }
}
public static readonly DependencyProperty ClearFilterStringProperty =
DependencyProperty.Register("ClearFilterString", typeof(string), typeof(ClearFilterButton), new PropertyMetadata("", ClearFilterString_PropertyChangedCallback));
public static readonly DependencyProperty ClearFilterActionProperty =
DependencyProperty.Register("ClearFilterAction", typeof(RelayCommand), typeof(ClearFilterButton), new PropertyMetadata(null, ClearFilterAction_PropertyChangedCallback));
private static void ClearFilterString_PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//empty
}
private static void ClearFilterAction_PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//empty
}
}
and User Control XAML:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" xmlns:GalaSoft_MvvmLight_Command="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WP71"
mc:Ignorable="d"
x:Class="ATTCookBook.ClearFilterButton"
d:DesignWidth="75" d:DesignHeight="75"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid x:Name="LayoutRoot" Background="Transparent">
<Button HorizontalAlignment="Center" VerticalAlignment="Center" BorderBrush="{x:Null}" Width="75" Height="75">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<GalaSoft_MvvmLight_Command:EventToCommand Command="{Binding ClearFilterAction, Mode=TwoWay}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<Button.Background>
<ImageBrush Stretch="UniformToFill" ImageSource="/icons/appbar.refresh.rest.png"/>
</Button.Background>
</Button>
<TextBlock HorizontalAlignment="Center" Margin="0,0,0,8" TextWrapping="Wrap" Text="{Binding ClearFilterString, Mode=TwoWay}" VerticalAlignment="Bottom" FontSize="13.333" Height="18" Width="0" d:LayoutOverrides="VerticalAlignment"/>
</Grid>
Now when I add this User Control to the Main Page and databind the two View Model Properties through to the User control it gets very weird:
<local:ClearFilterButton Height="Auto" Width="Auto" ClearFilterAction="{Binding ClearFilteredCategories, Mode=TwoWay}" ClearFilterString="{Binding ClearFilterText, Mode=TwoWay}"/>
Because although the Databinding statements above seem fine, the Binding errors with:
System.Windows.Data Error: BindingExpression path error: ‘ClearFilteredCategories’ property not found on ‘ATTCookBook.ClearFilterButton’ ‘ATTCookBook.ClearFilterButton’ (HashCode=126600431). BindingExpression: Path=’ClearFilteredCategories’ DataItem=’ATTCookBook.ClearFilterButton’ (HashCode=126600431); target element is ‘ATTCookBook.ClearFilterButton’ (Name=”); target property is ‘ClearFilterAction’ (type ‘GalaSoft.MvvmLight.Command.RelayCommand’)..
System.Windows.Data Error: BindingExpression path error: ‘ClearFilterText’ property not found on ‘ATTCookBook.ClearFilterButton’ ‘ATTCookBook.ClearFilterButton’ (HashCode=126600431). BindingExpression: Path=’ClearFilterText’ DataItem=’ATTCookBook.ClearFilterButton’ (HashCode=126600431); target element is ‘ATTCookBook.ClearFilterButton’ (Name=”); target property is ‘ClearFilterString’ (type ‘System.String’)..
Which seems to indicate the View Model is trying to find the parent properties in the child user control?
I do not understand why this could be because I have set a Relative Data Context within the child user control to avoid this and the binding should be passing through the two dependency properties.
I was hoping to make the user control more generic later but cannot seem to even get it working in a basic fashion
Quick call out to you Silverlight Binding masters 😀
Resolved in the end with some thanks to the above, however the answer was a lot simpler.
All I had to do was remove any mention of Modes (remove Mode=”TwoWay”) and remove the DataContext setting from the user control and it just worked.
Just goes to show it’s very easy to over-engineer a solution.
I Suspect by adding the Mode setting it was trying to pass the datacontext through the binding and that what it was throwing up (not a very helpful error message)
Hope this helps others. Just keep it simple and work up from there.
For those that are interested, I was basing the implementation from this very useful post – Silverlight UserControl Custom Property Binding