Как использовать свойство зависимостей пользовательского элемента управления при настройке контекста данных? - PullRequest
3 голосов
/ 06 июля 2019

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

<local:myUserControl Command="{Binding someCommand}"/>

myCommand - это свойство зависимости, которое я создал для этого пользовательского элемента управления. И я связываю это с командой модели представления главного окна ("someCommand").

Проблема в том, что я устанавливаю текстовый код моего usercontrol (у меня есть модель представления для него), и кажется, что для «Команды» устанавливается ноль… Вот код позади моей модели представления:

public partial class myUserControl : UserControl, ICommandSource
{
    public myUserControl()
    {
        this.DataContext = new myViewModel();

        InitializeComponent();
    }

    public ICommand Command
    {
        get { return (ICommand)GetValue(CommandProperty); }
        set { SetValue(CommandProperty, value); }
    }
    public static readonly DependencyProperty CommandProperty =
        DependencyProperty.Register("Command", typeof(ICommand), typeof(myUserControl), new PropertyMetadata(null));



    public object CommandParameter
    {
        get { return (object)GetValue(CommandParameterProperty); }
        set { SetValue(CommandParameterProperty, value); }
    }
    public static readonly DependencyProperty CommandParameterProperty =
        DependencyProperty.Register("CommandParameter", typeof(object), typeof(myUserControl), new PropertyMetadata(0));



    public IInputElement CommandTarget
    {
        get { return (IInputElement)GetValue(CommandTargetProperty); }
        set { SetValue(CommandTargetProperty, value); }
    }
    public static readonly DependencyProperty CommandTargetProperty =
        DependencyProperty.Register("CommandTarget", typeof(IInputElement), typeof(myUserControl), new PropertyMetadata(null));



    private void TextBlock_MouseUp(object sender, MouseButtonEventArgs e)
    {
        Command.Execute(this.CommandParameter);
    }
}

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

<UserControl x:Class="myApp.myUserControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:myApp"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <TextBlock MouseUp="TextBlock_MouseUp">
        </TextBlock>
    </Grid>
</UserControl>

(я знаю, что этот элемент кажется немного глупым (или бесполезным), но я упростил его, чтобы проверить, что не сработало, а также чтобы задать довольно простой вопрос).

Я обнаружил, что если я прокомментирую «this.DataContext = new myViewModel ();» строка, привязка к команде работает отлично. И когда я раскомментирую эту строку и добавлю точку останова в «TextBlock_MouseUp», свойство «Command» будет равно нулю ...

Был бы способ решить эту проблему? У меня есть некоторый сложный код в моей модели представления (поэтому я вынужден оставить эту строку "this.DataContext = new myViewModel ();"), и я не уверен, что смогу найти другое решение, кроме наличия зависимости "Command" собственность в моем пользовательском контроле…

Чтобы быть уверенным, что я предоставляю максимум информации, в модели представления моего главного окна есть следующий код:


public ICommand someCommand { get; set; }

//Constructor
public MainWindowViewModel()
{
    this.someCommand = new RelayCommand((obj) => { return true; },
                                        (obj) =>
                                        {
                                            //I put a breakpoint here
                                            int dummy = 0;
                                        });
}

(Класс RelayCommand является стандартным классом RelayCommand с CanExecute «Предикат» и «Выполнение действия»).

Надеюсь, этот вопрос не является дубликатом ... Я нашел несколько похожих вопросов, но они, похоже, не отвечали на мои ...

1 Ответ

1 голос
/ 06 июля 2019

Мне действительно жаль этот вопрос, который был немного глупым.Я не очень хорошо понял, что происходит во время переплета.Я думал, что эта строка кода в MainWindow…

<local:myUserControl Command="{Binding someCommand}"/>

… сделала бы попытку связать свойство «Command» в UserControl с «someCommand» в текстовом тексте MainWindow ,На самом деле, как указал @elgonzo, привязка ищется в тексте данных *1007* UserControl для свойства someCommand (а не в текстовом тексте MainWindow !!).Таким образом, установка контекста данных UserControl с помощью этой строки…

this.DataContext = new myViewModel();

... препятствовала правильному выполнению привязки (так как он ищет свойство «someCommand» в datacontext объекта UserControl, которое теперь называется myViewModel)", который не содержит" someCommand "...).

Чтобы исправить это, мне пришлось изменить привязку следующим образом:

<local:myUserControl Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, 
                                       Path=DataContext.someCommand}"/>

Я нашел это решение здесь:https://stackoverflow.com/a/1127964/11609068.

Возможно, это не лучший способ сделать это («Path = DataContext. someCommand» заставляет меня думать, что это не очень элегантно), но этоработает.Другой способ сделать это - назвать MainWindow (x: Name = "someName"), чтобы привязка была немного проще:

<local:myUserControl Command="{Binding ElementName=someName, Path=DataContext.someCommand}"/>

Опять же, извините, большое спасибо @ elgonzo.

...