wpf ICommand 依赖属性
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28650304/
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
ICommand Dependency Property
提问by Xanagandr
I have an UserControl with a button inside. This button needs to add some items to a Grid that's inside said UC. I'm aware I can do this with a Click event.
我有一个里面有一个按钮的 UserControl。此按钮需要向 UC 内的网格添加一些项目。我知道我可以通过 Click 事件来做到这一点。
The issue here is I am using MVVM and altering data outside their corresponding ViewModel would break the format (So to say).
这里的问题是我正在使用 MVVM 并且在其相应的 ViewModel 之外更改数据会破坏格式(可以这么说)。
Is there a way to create an ICommand Dependency Property so I can bind said DP to the button and have the functionality of adding the item to the Grid in my ViewModel? (I already have the List in both my UC and my ViewModel and they are working as expected)
有没有办法创建 ICommand 依赖属性,以便我可以将所述 DP 绑定到按钮并具有将项目添加到我的 ViewModel 中的网格的功能?(我的 UC 和 ViewModel 中都已经有了 List,它们按预期工作)
Thank you.
谢谢你。
回答by Xanagandr
Found a way to solve it in the way I was trying to. Leaving the answer here so people may use it:
找到了一种以我尝试的方式解决它的方法。将答案留在这里,以便人们可以使用它:
1) In your User Control's code-behind, create a Dependency Property. I choose ICommand, since in my ViewModel I set it as a DelegateCommmand:
1) 在您的用户控件的代码隐藏中,创建一个依赖属性。我选择 ICommand,因为在我的 ViewModel 中我将它设置为 DelegateCommmand:
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register(
"Command",
typeof(ICommand),
typeof(UserControl));
public ICommand Command
{
get
{
return (ICommand)GetValue(CommandProperty);
}
set
{
SetValue(CommandProperty, value);
}
}
2) In your UserControl's XAML code, bind this Dependency Property (In this case, a button):
2) 在您的 UserControl 的 XAML 代码中,绑定此依赖项属性(在本例中为按钮):
<Grid DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}">
<Button Command="{Binding Command}" />
</Grid>
3) Next, on your ViewModel, declare a Command property and configure accordingly:
3) 接下来,在您的 ViewModel 上,声明一个 Command 属性并进行相应配置:
public ICommand ViewModelCommand { get; set; }
public ViewModelConstructor()
{
ViewModelCommand = new DelegateCommand(ViewModelCommandExecute);
}
private void ViewModelCommandExecute()
{
// Do something
}
4) Finally, on your View where the UserControl is nested, we declare the binding:
4) 最后,在嵌套 UserControl 的 View 上,我们声明绑定:
<UserControls:UserControl Command={Binding ViewModelCommand}/>
This way, the binding will take place and you can bind Commands from the buttons of any User Control to your ViewModels without breaking MVVM.
这样,绑定就会发生,您可以将来自任何用户控件按钮的命令绑定到您的 ViewModel,而不会破坏 MVVM。
回答by corradolab
The basic way is to create an Object (ie MyCommand) which implements ICommand, and nest it inside your ViewModel. Inside MyCommand you have no access to your ViewModel. You can workaround it (ie pass a reference to the ViewModel in MyCommand constructor) but at the end it's too much code (for simple stuff like this). I think almost nobody really do this.
基本方法是创建一个实现 ICommand 的对象(即 MyCommand),并将其嵌套在您的 ViewModel 中。在 MyCommand 中,您无法访问您的 ViewModel。您可以解决它(即在 MyCommand 构造函数中传递对 ViewModel 的引用),但最终代码太多(对于像这样的简单东西)。我认为几乎没有人真正做到这一点。
Most use a DelegateCommandwhich resolve (most of) the above issues.
大多数使用DelegateCommand解决(大部分)上述问题。
Last but not least, just use event handlers.
If you code them simply like this:
最后但并非最不重要的一点是,只需使用事件处理程序。
如果您像这样简单地对它们进行编码:
void Grid_MouseMove(object sender, MouseEventArgs e)
{ viewModel.SaveMousePosition(e.GetPosition()); }
you are not breaking any MVVM rule.
And you can't handle the above event with Commands.
There is no Command for MouseMove (there is none for most events), and you can't pass event parameters in a Command.
您没有违反任何 MVVM 规则。
并且您无法使用命令处理上述事件。
MouseMove 没有命令(对于大多数事件没有命令),并且您不能在命令中传递事件参数。
You can handle every event using Interaction.Triggers like this
But you still miss the capability to handle event parameters (and add ugly XAML).
您可以像这样使用 Interaction.Triggers 处理每个事件
但是您仍然错过了处理事件参数的能力(并添加了丑陋的 XAML)。
To me, until WPF will support databinding in event handlers, like
对我来说,直到 WPF 支持事件处理程序中的数据绑定,例如
Grid MouseMove="{Binding SaveMousePosition(e)}"
code behind is still the most effective way to handle events.
代码隐藏仍然是处理事件的最有效方式。
回答by Michael Snytko
I faced similar problem and this question/answers helped me the most; so I will post my solution here in case somebody else will google it later. Made with mvvm light.
我遇到了类似的问题,这个问题/答案对我帮助最大;所以我会在这里发布我的解决方案,以防其他人稍后用谷歌搜索。用 mvvm 灯制作。
I had a custom winforms control as a Model and a WPF control as a View. So, xaml of View (I have an usercontrol for my View, no app.xaml):
我有一个自定义的 winforms 控件作为模型,一个 WPF 控件作为视图。因此,视图的 xaml(我的视图有一个用户控件,没有 app.xaml):
<UserControl.Resources>
<ResourceDictionary>
<viewModel:ViewModelLocator x:Key="Locator" />
</ResourceDictionary>
</UserControl.Resources>
<UserControl.DataContext>
<Binding Path = "Main" Source="{StaticResource Locator}"></Binding>
</UserControl.DataContext>
<Grid>
<Button Command="{Binding Zoom, ElementName=Wrapper}"></Button>
<viewModel:ProfileWrapper x:Name="Wrapper" >
</viewModel:ProfileWrapper>
</Grid>
Click of a Button is routed to a RelayCommand Zoom in ProfileWrapper (which is where my Model implemented)
单击一个按钮被路由到 ProfileWrapper 中的 RelayCommand Zoom(这是我的模型实现的地方)
Then the xaml of ProfileWrapper is straghtforward:
然后 ProfileWrapper 的 xaml 是直接的:
<Grid>
<WindowsFormsHost>
<local:ManualControl x:Name="abc" ></local:ManualControl>
</WindowsFormsHost>
</Grid>
And the codebehind of ProfileWrapper :
ProfileWrapper 的代码隐藏:
public partial class ProfileWrapper : UserControl
{
public ProfileWrapper()
{
InitializeComponent();
test = abc;
Command = new RelayCommand(() => test.bZoomIn());
}
public ManualControl test;
public RelayCommand Zoom { get; set; }
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register(
"Zoom",
typeof(ICommand),
typeof(ProfileWrapper));
public ICommand Command
{
get
{
return (ICommand)GetValue(CommandProperty);
}
set
{
SetValue(CommandProperty, value);
}
}
}
My MainViewModel class is empty and all fuctionality goes to ProfileWrapper class, which might be bad, but at least it works.
我的 MainViewModel 类是空的,所有功能都转到 ProfileWrapper 类,这可能很糟糕,但至少它可以工作。

