【问题标题】:ICommand Dependency PropertyICommand 依赖属性
【发布时间】:2015-04-23 09:22:38
【问题描述】:

我有一个用户控件,里面有一个按钮。此按钮需要将一些项目添加到所述 UC 内部的网格中。我知道我可以通过 Click 事件来做到这一点。

这里的问题是我正在使用 MVVM 并且在其对应的 ViewModel 之外更改数据会破坏格式(可以这么说)。

有没有办法创建 ICommand 依赖属性,以便我可以将所述 DP 绑定到按钮并具有将项目添加到 ViewModel 中的网格的功能? (我的 UC 和 ViewModel 中都已经有列表,它们按预期工作)

谢谢。

【问题讨论】:

  • 用代码支持你的问题,而且很简单
  • 问题是我没有任何代码来支持我的问题,因为我不知道从哪里开始,而且我不知道这个问题可以简单得多。另一方面,我设法找到了解决方案。它已经在下面发布了。谢谢。

标签: c# wpf mvvm user-controls icommand


【解决方案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 类,这可能很糟糕,但至少它可以工作。

【讨论】:

    猜你喜欢
    • 2021-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-07
    • 1970-01-01
    • 2014-05-23
    相关资源
    最近更新 更多