Windows Phone的Silverlight:用户控件的BindingExpression路径错误 - 找不到属性

时间:2011-11-06 10:16:12

标签: silverlight windows-phone-7 data-binding mvvm mvvm-light

刚刚遇到一个非常奇怪的数据绑定问题,我似乎无法深入到底部:

情景 MVVM视图模型数据绑定到具有两个属性的父窗体

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

然后我有一个带有两个依赖属性的User控件,因此:

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

和用户控制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>

现在,当我将此用户控件添加到主页面并将两个视图模型属性数据绑定到用户控件时,它变得非常奇怪:

<local:ClearFilterButton Height="Auto" Width="Auto" ClearFilterAction="{Binding ClearFilteredCategories, Mode=TwoWay}" ClearFilterString="{Binding ClearFilterText, Mode=TwoWay}"/>

因为虽然上面的Databinding语句似乎很好,但Binding错误有:

  

System.Windows.Data错误:BindingExpression路径错误:在'ATTCookBook.ClearFilterButton''ATTCookBook.ClearFilterButton'(HashCode = 126600431)上找不到'ClearFilteredCategories'属性。 BindingExpression:Path ='ClearFilteredCategories'DataItem ='ATTCookBook.ClearFilterButton'(HashCode = 126600431); target元素是'ATTCookBook.ClearFilterButton'(Name =''); target属性是'ClearFilterAction'(类型'GalaSoft.MvvmLight.Command.RelayCommand')..

     

System.Windows.Data错误:BindingExpression路径错误:在'ATTCookBook.ClearFilterButton''ATTCookBook.ClearFilterButton'(HashCode = 126600431)上找不到'ClearFilterText'属性。 BindingExpression:Path ='ClearFilterText'DataItem ='ATTCookBook.ClearFilterButton'(HashCode = 126600431); target元素是'ATTCookBook.ClearFilterButton'(Name =''); target属性是'ClearFilterString'(类型'System.String')..

这似乎表明View Model正试图在子用户控件中找到父属性? 我不明白为什么会这样,因为我在子用户控件中设置了一个相对数据上下文来避免这种情况,并且绑定应该通过两个依赖属性。

我希望以后能让用户控制更通用,但似乎无法让它以基本方式运行

快速呼唤Silverlight Binding大师:D

3 个答案:

答案 0 :(得分:0)

在您的UserControl中,您正在重置Datacontext,现在是表达式

ClearFilterAction="{Binding ClearFilteredCategories, Mode=TwoWay}"

与您使用UserControl的页面相关,而与UserControl本身无关。当您想要引用在页面的VM上声明的公共命令而不是在绑定到模板的对象数据上时,您可能会遇到与ItemTemplate datacontext相同的问题。

您可以使用代理:

ClearFilterAction="{Binding Source={StaticResource 
DataContextProxy},Path=DataSource.ClearFilteredCategories}"

代理被声明为资源:

<Resources:DataContextProxy x:Key="DataContextProxy" />

和DataProxy类的代码:

public class DataContextProxy : FrameworkElement
{
    public DataContextProxy()
    {
        this.Loaded += new RoutedEventHandler(DataContextProxy_Loaded);
    }

    void DataContextProxy_Loaded(object sender, RoutedEventArgs e)
    {
        var binding = new Binding();
        if (!String.IsNullOrEmpty(BindingPropertyName))
        {
            binding.Path = new PropertyPath(BindingPropertyName);
        }
        binding.Source = this.DataContext;
        binding.Mode = BindingMode;
        this.SetBinding(DataContextProxy.DataSourceProperty, binding);
    }

    public Object DataSource
    {
        get { return (Object)GetValue(DataSourceProperty); }
        set { SetValue(DataSourceProperty, value); }
    }

    public static readonly DependencyProperty DataSourceProperty =
        DependencyProperty.Register("DataSource", typeof(Object), typeof(DataContextProxy), null);


    public string BindingPropertyName { get; set; }

    public BindingMode BindingMode { get; set; }

}

答案 1 :(得分:0)

将数据上下文的分配移动到usercontrol的根DataGrid

<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">

<Grid x:Name="LayoutRoot" Background="Transparent" DataContext="{Binding Parent, RelativeSource={RelativeSource Self}}" >
    <Button HorizontalAlignment="Center" VerticalAlignment="Center" BorderBrush="{x:Null}" Width="75" Height="75">

答案 2 :(得分:0)

最后得到了上述的解决,但答案要简单得多。

我所要做的就是删除任何提及Modes(删除Mode =“TwoWay”)并从用户控件中删除DataContext设置,它就可以了。

只是表明过度设计解决方案非常容易。

我怀疑通过添加模式设置,它试图通过绑定传递datacontext以及它抛出的内容(不是非常有用的错误消息)

希望这有助于他人。只需保持简单并从那里开始工作。

对于那些感兴趣的人,我基于这个非常有用的帖子实现了基础 - Silverlight UserControl Custom Property Binding