C# 如何在 wpf 的用户控件中使用命令绑定?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13035551/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use command bindings in user controls in wpf?
提问by Sam
In MainWindow the commandbinding works fine. In UserControl1 it doesnt work. Note the datacontext is set correctly as is evidenced by the content of the button which is the result of a binding.
在 MainWindow 中,命令绑定工作正常。在 UserControl1 中它不起作用。请注意,数据上下文设置正确,正如绑定结果的按钮内容所证明的那样。
I am not trying to bind the command in the usercontrol to a command in mainwindow or any other such trickery. I am just trying to replicate what I did in MainWindow in UserControl1.
我不想将用户控件中的命令绑定到主窗口中的命令或任何其他此类技巧。我只是想复制我在 UserControl1 的 MainWindow 中所做的事情。
MainWindow XAML
主窗口 XAML
<StackPanel>
<Button Content="Click Here" Command="{Binding ClickHereCommand}" Height="25" Width="90"></Button>
<local:UserControl1></local:UserControl1>
</StackPanel>
MainWindow Code Behind
背后的主窗口代码
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
用户控件 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>
UserControl Code Behind
背后的用户控制代码
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
}
采纳答案by kmatyaszek
It's the best solution:
这是最好的解决方案:
<Grid DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}" >
<Button Content="{Binding ButtonContent}" Command="{Binding ClickHereCommand}" Height="25" Width="90"></Button>
</Grid>
Other solutions:
其他解决方案:
You forgot set DataContextto UserControl1.
您忘记将DataContext设置为UserControl1。
public UserControl1()
{
InitializeComponent();
ClickHereCommand = new RoutedCommand();
CommandBindings.Add(new CommandBinding(ClickHereCommand, ClickHereExecuted));
ButtonContent = "Click Here";
this.DataContext = this;
}
And after this you must delete in UserControl1DataContext in Grid.
在此之后,您必须在 Grid中的UserControl1DataContext 中删除。
This:
这个:
<Grid DataContext="{Binding ElementName=root}" >
<Button Content="{Binding ButtonContent}" Command="{Binding ClickHereCommand}" Height="25" Width="90"></Button>
</Grid>
you must change to this:
你必须改成这样:
<Grid>
<Button Content="{Binding ButtonContent}" Command="{Binding ClickHereCommand}" Height="25" Width="90"></Button>
</Grid>
Solution without set DataContext in UserControl:
在 UserControl 中没有设置 DataContext 的解决方案:
You must change ButtonContent and ClickHereCommand to DependencyProperty.
您必须将 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));
And in ctor of UserControl1:
在 ctor 中UserControl1:
public UserControl1()
{
InitializeComponent();
ClickHereCommand = new RoutedCommand();
CommandBindings.Add(new CommandBinding(ClickHereCommand, ClickHereExecuted));
ButtonContent = "Click Here";
//this.DataContext = this;
}
回答by Sam
Here I am AGAIN almost two years after I posted this. I forgot about this little feature of WPF and sure enough it bit me again.
在我发布这篇文章将近两年后,我再次来到这里。我忘记了 WPF 的这个小功能,果然它又咬我了。
The answer marked above is partially correct but contains other content that is distracting and/or incorrect. For clarity I will highlight what the problem is and what the solution is. I'm doing this more for my benefit than yours because I'm sure I'll be back here in about sixteen months.
上面标记的答案部分正确,但包含其他分散注意力和/或不正确的内容。为了清楚起见,我将强调问题是什么以及解决方案是什么。我这样做是为了我的利益而不是你的利益,因为我确信我会在大约 16 个月后回到这里。
Here is the problem. Don't do this. Your bindings will all continue to work except for your routed commands:
这是问题所在。不要这样做。除了路由命令之外,您的绑定都将继续工作:
<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>
The solution is use relative source in setting the data context as follows:
解决方案是使用相对源来设置数据上下文,如下所示:
<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 .
我所问的问题的唯一答案是上面的答案(实际上可能还有其他答案,但在本问题中到目前为止尚未讨论)。具体来说:在用户控件中设置“DataContext = this”不是解决方案,实际上会破坏承载用户控件的控件中的绑定。此外,只有作为绑定目标的属性必须是依赖属性。这个建议是不正确的。

