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 依赖属性的主要内容,如果未能解决你的问题,请参考以下文章

WPF MVVM--事件绑定

WPF MVVM--事件绑定

WPF MVVM--事件绑定

ICommand 类型的 WPF 附加属性

WPF非依赖属性绑定的问题

WPF 依赖属性和附加属性