设置其数据上下文时如何使用用户控件依赖项属性?

时间:2019-07-06 11:14:23

标签: c# xaml mvvm user-controls dependency-properties

我已经制作了一个用户控件,其中包含一个命令,以响应特定事件而被调用。此命令是依赖项属性。我想像这样在主窗口中使用它:

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

“ myCommand”是我为此用户控件创建的依赖项属性。然后将其绑定到主窗口视图模型的命令(“ someCommand”)。

问题是我正在设置用户控件的数据上下文(我有一个视图模型),并且似乎将“ Command”重置为null…这是我的视图模型的代码:

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”属性等于null ...

有没有办法解决这个问题?我的视图模型中有一些复杂的代码(因此我被迫保留这一行“ 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 个答案:

答案 0 :(得分:1)

对于这个问题,我真的很抱歉,这有点愚蠢。我不太了解绑定期间会发生什么。我以为这段代码在MainWindow中……

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

…将尝试将UserControl的“ Command”属性绑定到 MainWindow 的数据上下文的“ someCommand”。实际上,正如@elgonzo指出的那样,该绑定在 UserControl的数据上下文中查找“ someCommand”属性(而不是在MainWindow的datacontext中!)。因此,使用此行设置UserControl的数据上下文...

this.DataContext = new myViewModel();

...正在阻止正确完成绑定(因为它正在查找UserControl的数据上下文的“ someCommand”属性,现在为“ 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。