ICommand 依赖属性
Posted
技术标签:
【中文标题】ICommand 依赖属性【英文标题】:ICommand Dependency Property 【发布时间】:2015-04-23 09:22:38 【问题描述】:我有一个用户控件,里面有一个按钮。此按钮需要将一些项目添加到所述 UC 内部的网格中。我知道我可以通过 Click 事件来做到这一点。
这里的问题是我正在使用 MVVM 并且在其对应的 ViewModel 之外更改数据会破坏格式(可以这么说)。
有没有办法创建 ,以便我可以将所述 DP 绑定到按钮并具有将项目添加到 ViewModel 中的网格的功能? (我的 UC 和 ViewModel 中都已经有列表,它们按预期工作)
谢谢。
【问题讨论】:
用代码支持你的问题,而且很简单 问题是我没有任何代码来支持我的问题,因为我不知道从哪里开始,而且我不知道这个问题可以简单得多。另一方面,我设法找到了解决方案。它已经在下面发布了。谢谢。 【参考方案1】:找到了一种以我尝试的方式解决它的方法。在这里留下答案,以便人们可以使用它:
1) 在用户控件的代码隐藏中,创建一个依赖属性。我选择 ICommand,因为在我的 ViewModel 中我将它设置为 DelegateCommand:
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) 在您的 UserControl 的 XAML 代码中,绑定此依赖属性(在本例中为按钮):
<Grid DataContext="Binding RelativeSource=RelativeSource Mode=FindAncestor, AncestorType=x:Type UserControl">
<Button Command="Binding Command" />
</Grid>
3) 接下来,在您的 ViewModel 上,声明一个 Command 属性并进行相应的配置:
public ICommand ViewModelCommand get; set;
public ViewModelConstructor()
ViewModelCommand = new DelegateCommand(ViewModelCommandExecute);
private void ViewModelCommandExecute()
// Do something
4) 最后,在嵌套 UserControl 的 View 上,我们声明绑定:
<UserControls:UserControl Command=Binding ViewModelCommand/>
这样,绑定就会发生,您可以将任何用户控件的按钮中的命令绑定到您的 ViewModel,而不会破坏 MVVM。
【讨论】:
我收到以下错误消息:WPF 错误 40 BindingExpression 路径错误:在“对象”上找不到属性。 2号)解决了我的问题。我错过了 DataContext。 我创建了一个简单的应用程序,它显示了所描述代码的工作版本。 Sample 如何将参数从用户控件传递给命令,就像 DataGridView 对其 SelectedItem 所做的那样?【参考方案2】:基本的方法是创建一个实现 ICommand 的对象(即 MyCommand),并将其嵌套在您的 ViewModel 中。在 MyCommand 中,您无法访问您的 ViewModel。您可以解决它(即在 MyCommand 构造函数中传递对 ViewModel 的引用),但最后它的代码太多(对于像这样的简单东西)。我认为几乎没有人真正做到这一点。
大多数使用DelegateCommand 来解决(大部分)上述问题。
最后但同样重要的是,只需使用事件处理程序。 如果你像这样简单地编码它们:
void Grid_MouseMove(object sender, MouseEventArgs e)
viewModel.SaveMousePosition(e.GetPosition());
您没有违反任何 MVVM 规则。 而且您无法使用 Commands 处理上述事件。 MouseMove 没有命令(大多数事件没有命令),并且您不能在命令中传递事件参数。
您可以使用 Interaction.Triggers 处理每个事件,例如 this 但是您仍然无法处理事件参数(并添加丑陋的 XAML)。
对我来说,直到 WPF 支持事件处理程序中的数据绑定,例如
Grid MouseMove="Binding SaveMousePosition(e)"
代码隐藏仍然是处理事件的最有效方式。
【讨论】:
感谢您的回答。问题是我试图避免使用事件处理程序,因为我也在使用 MEF。我已经找到了我的问题的答案,但还是谢谢。 只是想指出,DelegateCommand
有时也被称为 RelayCommand
,对于那些可能想了解更多信息的人来说【参考方案3】:
我遇到了类似的问题,这个问题/答案对我帮助最大;所以我会在这里发布我的解决方案,以防其他人稍后用谷歌搜索它。使用 mvvm light 制作。
我有一个自定义 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>
按钮的点击被路由到 ProfileWrapper 中的 RelayCommand Zoom(这是我的模型实现的地方)
那么ProfileWrapper的xaml就直截了当:
<Grid>
<WindowsFormsHost>
<local:ManualControl x:Name="abc" ></local:ManualControl>
</WindowsFormsHost>
</Grid>
还有 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);
我的 MainViewModel 类是空的,所有功能都转到 ProfileWrapper 类,这可能很糟糕,但至少它可以工作。
【讨论】:
以上是关于ICommand 依赖属性的主要内容,如果未能解决你的问题,请参考以下文章