【问题标题】:Cannot pass/bind command to WPF user control无法将命令传递/绑定到 WPF 用户控件
【发布时间】:2011-10-31 17:15:02
【问题描述】:

我正在尝试将命令传递给 WPF 用户控件中的元素。

<UserControl x:Class="MyApp.MyControl"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <!-- shortened -->
    <Button Command="{Binding Command}">
        <Button.Content>
            <!-- shortened -->
        </Button.Content>
    </Button>
</UserControl>
public partial class MyControl : UserControl
{
   public static readonly DependencyProperty CommandProperty
      = DependencyProperty.Register("Command", 
                                           typeof(ICommand), typeof(MyControl));
   //shortened        
   public ICommand Command
   {
      get { return (ICommand)GetValue(CommandProperty); }
      set { SetValue(CommandProperty, value); }
   }
   //shortened
} 
<uc:MyControl Command="{Binding DoStuffCommand}" />  <!-- shortened -->

单击用户控件中的按钮时,没有任何反应。
当我调试时,Command 属性为空。
将命令绑定到用户控件外部的按钮确实有效。
这里出了什么问题?

【问题讨论】:

    标签: wpf binding user-controls command dependency-properties


    【解决方案1】:

    Button 的默认 DataContext 是您的 UserControl 的 DataContext,而不是您的 UserControl,因此您尝试绑定到 DataContext.Command 而不是 UserControl.Command

    要绑定到UserControl.Command,请使用RelativeSource 绑定

    <Button Command="{Binding Command, RelativeSource={
            RelativeSource AncestorType={x:Type local:MyControl}}}">  
    

    编辑刚刚注意到HB's answer,它也可以。通常我更喜欢 RelativeSource 绑定而不是 ElementName 绑定,因为有时我重命名项目并且习惯于忘记其他控件按名称引用该项目

    【讨论】:

    • 我忘了说用户控件构造函数是这样的:code public MyControl() { InitializeComponent();数据上下文 = 这个; } code 另一个绑定元素,一个字符串字段工作得很好,它是不起作用的命令。我在模拟什么吗?
    • 正如我提到的,用户控件中的Command属性在调试时为null。该命令确实存在,并且将其绑定到按钮而不是用户控件确实有效。
    • @David 如果您使用我在答案中的RelativeSource 绑定而不是您在问题中使用的简单绑定,该命令是否正常工作?
    • @David 在您的应用程序运行时使用Snoop 之类的工具,看看您的用户控件和按钮的DataContext 是什么。它可能会为您提供有关绑定失败的线索。 snoopwpf.codeplex.com
    【解决方案2】:

    为控件命名并使用ElementName:

    <UserControl ...
                 Name="control">
        <Button Command="{Binding Command, ElementName=control}">
        <!-- ... -->
    

    【讨论】:

    • 请查看 Rachel 帖子的回复
    【解决方案3】:

    好吧,我只是绑定到来自主机控件/窗口的命令。因为数据上下文将从它继承。像这样。

    <UserControl x:Class="MyApp.MyControl" 
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 
        <!-- shortened --> 
        <Button Command="{Binding DoStuffCommand}"> 
            <Button.Content> 
                <!-- shortened --> 
            </Button.Content> 
        </Button> 
    </UserControl>
    

    然后您可以从代码隐藏文件中删除依赖属性代码。

    并移除命令属性绑定,

    <uc:MyControl />
    

    【讨论】:

    • 坏主意,因为 UserControl 的 DataContext 中可能不一定有 DoStuffCommand
    • 显然,如果数据上下文的属性不存在,它将无法工作。但是,我不同意这是一个坏主意。您需要更多信息来确定这是否真的是一个坏主意。我只是想为这个问题提供一个解决方案。
    • 如果您希望此 UserControl 始终与特定的 ViewModel 一起使用,我想这不是问题,但是如果此 UserControl 是控件库的一部分,我觉得这是个坏主意跨度>
    • 我能理解。我还认为简化的数据绑定表达式和从用户控件代码隐藏中删除 depencey 属性实际上降低了我喜欢的复杂性。
    • 我同意 Brad 的观点,您可以设置 ElementName 属性或在消费者代码的视图模型中定义具有相同名称的委托命令 (DoStuffCommand)。
    【解决方案4】:

    总的来说,我总是遵循 Rachel 的建议(如上面的 one)。但在这种特殊情况下,我会考虑在用户控件的根元素上设置DataContext,然后它会在那里进行整洁的绑定。

    <Grid DataContext="{Binding RelativeSource={RelativeSource FindAncestor,
                                AncestorType={x:Type UserControl}}}">
    <!-- shortened -->
        <Button Command="{Binding Command}">
            <Button.Content>
                <!-- shortened -->
            </Button.Content>
        </Button>
    </Grid >
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-21
      • 2013-02-11
      • 2011-08-18
      • 1970-01-01
      • 2021-11-05
      • 1970-01-01
      • 1970-01-01
      • 2012-06-11
      相关资源
      最近更新 更多