9

在 MainWindow 中,命令绑定工作正常。在 UserControl1 中它不起作用。请注意,数据上下文设置正确,这是绑定结果的按钮内容所证明的。

我不想将用户控件中的命令绑定到主窗口中的命令或任何其他此类诡计。我只是想复制我在 UserControl1 的 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");
    }
}

用户控件 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
}
4

2 回答 2

14

这是最好的解决方案:

 <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));

在 ctor 中UserControl1

 public UserControl1()
    {
        InitializeComponent();

        ClickHereCommand = new RoutedCommand();
        CommandBindings.Add(new CommandBinding(ClickHereCommand, ClickHereExecuted));            
        ButtonContent = "Click Here";
        //this.DataContext = this;
    }
于 2012-10-23T17:27:04.810 回答
11

在我发布这篇文章将近两年后,我又来了。我忘记了 WPF 的这个小功能,果然它又咬了我一口。

上面标记的答案部分正确,但包含其他令人分心和/或不正确的内容。为了清楚起见,我将强调问题是什么以及解决方案是什么。我这样做是为了我的利益而不是为了你的利益,因为我确信我会在大约 16 个月后回到这里。

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

<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>

The only answer to the problem I asked about is the one above (there may in fact be other answers but they are not discussed thus far in this question). Specifically: Setting "DataContext = this" in the usercontrol is NOT a solution and will in fact break bindings in the control that hosts the user control. Also, only properties that are the targets of bindings must be dependency properties. That suggestion is incorrect .

于 2014-08-02T00:29:37.490 回答