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

How to use a user control dependency property when setting its data context?

我制作了一个用户控件,其中包含一个命令,可以调用它来响应某个事件。此命令是一个依赖项 属性。我想像这样在主要 window 中使用它:

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

"myCommand" 是我为此用户控件创建的依赖关系 属性。我将它绑定到主视图模型的命令 window ("someCommand").

问题是我正在设置我的用户控件的数据上下文(我有一个视图模型),它似乎将 "Command" 重置为空...这是我视图的代码隐藏型号:

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" 依赖项 属性 在我的用户控件中…

为了确保我提供最多的信息,我在主 window 的视图模型中有以下代码:


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 class 是标准 RelayCommand class,带有 "Predicate" CanExecute 和“Action Execute”。

我希望这个问题不是重复的……我发现了几个类似的问题,但他们似乎没有回答我的……

对于这个实际上有点愚蠢的问题,我真的很抱歉。我不太了解绑定过程中会发生什么。我认为 MainWindow 中的这段代码行......

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

…会尝试将 UserControl 的 "Command" 属性 绑定到 MainWindow 的数据上下文的 "someCommand"。事实上,正如@elgonzo 指出的那样,绑定在 UserControl 的 数据上下文中查找 "someCommand" 属性(而不是在 MainWindow 的数据上下文中!!)。因此,用这一行设置 UserControl 的数据上下文…

this.DataContext = new myViewModel();

...阻止正确完成绑定(因为它查找用户控件数据上下文的 "someCommand" 属性,现在是 "myViewModel",其中不包含"someCommand"...).

为了解决这个问题,我必须像这样更改绑定:

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

我在这里找到了这个解决方案:。

也许这不是最好的方法("Path= DataContext. someCommand" 让我这么想,它看起来不太优雅),但它确实有效。另一种方法是命名 MainWindow (x:Name="someName"),这样绑定就更简单了:

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

再次抱歉,非常感谢@elgonzo。