Silverlight для Windows Phone: ошибка пути BindingExpression с пользовательским элементом управления - свойство не найдено - PullRequest
2 голосов
/ 06 ноября 2011

Просто попробуйте решить очень странную проблему с привязкой данных, которую я не могу понять:

Сценарий 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);
        }
    }

Тогда у меня есть пользовательский элемент управления с двумя свойствами зависимостей, таким образом:

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

Поскольку приведенные выше операторы привязки данных выглядят хорошо, ошибки привязки с:

Ошибка System.Windows.Data: ошибка пути BindingExpression: свойство 'ClearFilteredCategories' не найдено в 'ATTCookBook.ClearFilterButton' 'ATTCookBook.ClearFilterButton' (HashCode = 126600431).BindingExpression: Path = 'ClearFilteredCategories' DataItem = 'ATTCookBook.ClearFilterButton' (HashCode = 126600431);целевым элементом является 'ATTCookBook.ClearFilterButton' (Name = '');целевым свойством является «ClearFilterAction» (тип «GalaSoft.MvvmLight.Command.RelayCommand») ..

System.Windows.Data Ошибка: ошибка пути BindingExpression: свойство «ClearFilterText» не найдено в «ATTCookBook.ClearFilterButton»ATTCookBook.ClearFilterButton '(HashCode = 126600431).BindingExpression: Path = 'ClearFilterText' DataItem = 'ATTCookBook.ClearFilterButton' (HashCode = 126600431);целевым элементом является 'ATTCookBook.ClearFilterButton' (Name = '');Свойство target - ClearFilterString (тип System.String) ..

Что, по-видимому, указывает на то, что View View пытается найти родительские свойства в дочернем пользовательском элементе управления?Я не понимаю, почему это может быть связано с тем, что я установил относительный контекст данных в дочернем пользовательском элементе управления, чтобы избежать этого, и привязка должна проходить через два свойства зависимостей.

Я надеялся создать пользовательский элемент управленияболее общий позже, но, кажется, даже не может заставить его работать базовым образом

Быстрый вызов мастерам Silverlight Binding: D

Ответы [ 3 ]

0 голосов
/ 06 ноября 2011

Переместить назначение контекста данных в корень 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">
0 голосов
/ 07 ноября 2011

Решено в конце, благодаря некоторому вышеизложенному, однако ответ был намного проще.

Все, что мне нужно было сделать, это удалить упоминание о режимах (remove Mode = "TwoWay") и удалить параметр DataContext из пользовательского элемента управления, и он просто заработал.

Это просто говорит о том, что очень легко перегрузить решение.

Подозреваю, добавив параметр Mode, он пытался пропустить текст данных через привязку и то, что он выбрасывал (не очень полезное сообщение об ошибке)

Надеюсь, это поможет другим. Просто будь проще и работай оттуда.

Для тех, кто заинтересован, я основывал реализацию на этом очень полезном посте - Привязка пользовательского свойства Silverlight UserControl

0 голосов
/ 06 ноября 2011

В вашем UserControl вы сбрасываете Datacontext, так что теперь выражение

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

относится не к Странице, на которой вы используете UserControl, а к самому UserControl. Вы можете столкнуться с той же проблемой с текстовым текстом ItemTemplate, если хотите сослаться на общую команду, объявленную на виртуальной машине страницы, а не на данных объекта, привязанных к шаблону.

Вы можете использовать прокси:

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

}
...