如何在wpf中的用户控件中使用命令绑定?

时间:2012-10-23 16:56:48

标签: c# .net wpf

在MainWindow中,命令绑定工作正常。 在UserControl1中它不起作用。请注意,datacontext设置正确,因为按钮的内容是绑定的结果。

我没有尝试将usercontrol中的命令绑定到mainwindow中的命令或任何其他此类欺骗。我只是想在UserControl1中复制我在MainWindow中所做的事情。

MainWindow XAML

<StackPanel>
    <Button Content="Click Here" Command="{Binding ClickHereCommand}" Height="25" Width="90"></Button>
    <local:UserControl1></local:UserControl1>
</StackPanel>

MainWindow代码背后

public partial class MainWindow : Window
{
    public static RoutedCommand ClickHereCommand { get; set; }

    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = this;
        ClickHereCommand = new RoutedCommand();
        CommandBindings.Add(new CommandBinding(ClickHereCommand, ClickHereExecuted));
    }

    public void ClickHereExecuted(object sender, ExecutedRoutedEventArgs e)
    {
        System.Windows.MessageBox.Show("hello");
    }
}

UserControl XAML

<UserControl x:Class="CommandBindingTest.UserControl1"
         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" 
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300" x:Name="root">

<Grid DataContext="{Binding ElementName=root}" >
    <Button Content="{Binding ButtonContent}" Command="{Binding ClickHereCommand}" Height="25" Width="90"></Button>
</Grid>
</UserControl>

用户控制代码

public partial class UserControl1 : UserControl, INotifyPropertyChanged
{
    private string _ButtonContent;
    public string ButtonContent
    {
        get { return _ButtonContent; }
        set
        {
            if (_ButtonContent != value)
            {
                _ButtonContent = value;
                OnPropertyChanged("ButtonContent");
            }
        }
    }

    public static RoutedCommand ClickHereCommand { get; set; }


    public UserControl1()
    {
        InitializeComponent();
        ClickHereCommand = new RoutedCommand();
        CommandBindings.Add(new CommandBinding(ClickHereCommand, ClickHereExecuted));
        ButtonContent = "Click Here";
    }

    public void ClickHereExecuted(object sender, ExecutedRoutedEventArgs e)
    {
        System.Windows.MessageBox.Show("hello from UserControl1");
    }


    #region INotifyPropertyChanged Members
    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged(string name)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
    }
    #endregion
}

2 个答案:

答案 0 :(得分:13)

这是最好的解决方案:

 <Grid DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}" >
        <Button Content="{Binding ButtonContent}" Command="{Binding ClickHereCommand}" Height="25" Width="90"></Button>
 </Grid>

其他解决方案:

您忘了将 DataContext 设置为 UserControl1

  public UserControl1()
        {
            InitializeComponent();
            ClickHereCommand = new RoutedCommand();
            CommandBindings.Add(new CommandBinding(ClickHereCommand, ClickHereExecuted));
            ButtonContent = "Click Here";
            this.DataContext = this;
        }

在此之后,您必须删除Grid中的 UserControl1 DataContext。

此:

<Grid DataContext="{Binding ElementName=root}" >
    <Button Content="{Binding ButtonContent}" Command="{Binding ClickHereCommand}" Height="25" Width="90"></Button>
</Grid>

你必须改为:

<Grid>
        <Button Content="{Binding ButtonContent}" Command="{Binding ClickHereCommand}" Height="25" Width="90"></Button>
</Grid>

在UserControl中没有设置DataContext的解决方案:

您必须将ButtonContent和ClickHereCommand更改为DependencyProperty。

        public string ButtonContent
        {
            get { return (string)GetValue(ButtonContentProperty); }
            set { SetValue(ButtonContentProperty, value); }
        }

        public static readonly DependencyProperty ButtonContentProperty =
            DependencyProperty.Register("ButtonContent", typeof(string), typeof(UserControl1), new UIPropertyMetadata(string.Empty));

        public RoutedCommand ClickHereCommand
        {
            get { return (RoutedCommand)GetValue(ClickHereCommandProperty); }
            set { SetValue(ClickHereCommandProperty, value); }
        }

        public static readonly DependencyProperty ClickHereCommandProperty =
            DependencyProperty.Register("ClickHereCommand", typeof(RoutedCommand), typeof(UserControl1), new UIPropertyMetadata(null));

UserControl1的代理商中:

 public UserControl1()
    {
        InitializeComponent();

        ClickHereCommand = new RoutedCommand();
        CommandBindings.Add(new CommandBinding(ClickHereCommand, ClickHereExecuted));            
        ButtonContent = "Click Here";
        //this.DataContext = this;
    }

答案 1 :(得分:11)

我发布此消息后差不多两年了。我忘记了WPF的这个小功能,果然它再次让我感到厌烦。

上面标记的答案部分正确,但包含其他分散注意力和/或不正确的内容。为清楚起见,我将重点介绍问题所在以及解决方案的内容。为了我的利益,我这样做比你的更多,因为我相信我会在大约十六个月内回到这里。

这是问题所在。不要这样做。除了路由命令之外,您的绑定将继续有效:

<UserControl x:Class="CommandBindingTest.UserControl1"
     // snip
     d:DesignHeight="300" d:DesignWidth="300" x:Name="root">

    <Grid DataContext="{Binding ElementName=root}" >
        <Button Content="{Binding ButtonContent}" Command="{Binding ClickHereCommand}" Height="25" Width="90">
        </Button>
    </Grid>

解决方案是使用相对源来设置数据上下文,如下所示:

<Grid DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}" >
    <Button Content="{Binding ButtonContent}" Command="{Binding ClickHereCommand}" Height="25" Width="90">
    </Button>
</Grid>

我问过的问题的唯一答案是上面的问题(事实上可能有其他答案,但到目前为止这个问题还没有讨论过)。 特别: 在usercontrol中设置“DataContext = this”不是解决方案,实际上会破坏托管用户控件的控件中的绑定。 此外,只有作为绑定目标的属性必须是依赖项属性。这个建议是不正确的。