【问题标题】:How to use a user control dependency property when setting its data context?设置数据上下文时如何使用用户控件依赖属性?
【发布时间】:2019-11-16 16:59:54
【问题描述】:

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

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

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

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

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 类,具有“Predicate” CanExecute 和“Action Execute”)。

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

【问题讨论】:

  • 未明确指定绑定源对象的绑定将查看 DataContext 属性提供的对象。请注意,DataContext 属性是一个继承 属性。如果您没有在用户控件中设置 DataContext,那么那里的命令绑定将使用从其父容器 DataContext“继承”的任何对象 DataContext。因此,基本上在用户控件中设置与不设置 DataContext 会更改绑定将尝试访问“someCommand”属性的对象。如果您的 myViewModel 实例没有“someCommand”属性:null
  • aha,所以@elgonzo 这意味着即使我在MainWindow 中设置Command="{Binding someCommand}" 绑定,它也会在UserControl 中查找的数据上下文?因此,如果我不设置 UserControl 的 DataContext,它会继承 MainWindow 中的一个,确实包含一些命令,但如果我设置 UserControl 的 DataContext,它不会继承 MainWindow 数据上下文,所以不再包含 someCommand 了?对吗?
  • 是的,除非您为绑定明确指定某个源,否则在尝试解析给定路径/属性(“someCommand”)时,绑定将查找绑定目标对象的 DataContext。在您的情况下,绑定目标是用户控件的 Command DependencyProperty,因此绑定将尝试在用户控件的 DataContext 提供的对象中查找“someCommand”属性。您在上一条评论中所说的一切都是正确的。 :-)
  • @elgonzo 哦哦!非常感谢!请为缺乏知识道歉:似乎我不太了解绑定是如何制作的……再次感谢!你想为此做一个答案(以获得一些分数),还是我应该用最终有效的代码来编写它?
  • 随意使用您的代码示例进行自我回答(自我回答问题完全可以。谁写答案并不重要。)顺便说一句,我只是在Binding.Source 的官方文档和微软自己的 WPF 绑定指南/概述,我很惊讶没有找到任何说明这种“默认源”行为的内容。不过,我只是在浏览文档,所以也许我只是忽略了一些东西。 (如果你不回答,当我能找到一些关于它的参考文档时,我会在周末的某个时候写一个答案)

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


【解决方案1】:

我真的很抱歉这个问题实际上有点愚蠢。我不太了解绑定期间会发生什么。我以为MainWindow中的这行代码……

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

...会尝试将 UserControl 的“Command”属性绑定到 MainWindow 的数据上下文的“someCommand”。事实上,正如@elgonzo 指出的那样,绑定在 UserControl 的 数据上下文中查找“someCommand”属性(而不是在 MainWindow 的数据上下文中!!)。因此,用这一行设置 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。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-04
    • 1970-01-01
    • 1970-01-01
    • 2012-12-06
    相关资源
    最近更新 更多