ICommand依赖属性

时间:2015-02-21 19:28:13

标签: c# wpf mvvm user-controls icommand

我有一个带有按钮的UserControl。此按钮需要将一些项目添加到所述UC内部的网格中。我知道我可以用Click事件做到这一点。

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

有没有办法创建ICommand依赖属性,这样我就可以将所述DP绑定到按钮,并具有在ViewModel中将项添加到Grid的功能? (我已经在我的UC和我的ViewModel中都有了List,并且它们正在按预期工作)

谢谢。

3 个答案:

答案 0 :(得分:12)

找到了一种方法,以我试图的方式解决它。留下答案,以便人们可以使用它:

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)在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)最后,在ViewControl嵌套的View上,我们声明绑定:

<UserControls:UserControl Command={Binding ViewModelCommand}/>

这样,就会发生绑定,您可以将命令从任何用户控件的按钮绑定到ViewModel而不会破坏MVVM。

答案 1 :(得分:0)

基本方法是创建一个实现ICommand的Object(即MyCommand),并将其嵌套在ViewModel中。在MyCommand中,您无法访问ViewModel。你可以解决它(即在MyCommand构造函数中传递对ViewModel的引用),但最后它的代码太多了(对于像这样的简单东西)。我想几乎没有人真的这样做。

大多数人使用DelegateCommand来解决(大部分)上述问题。

最后但并非最不重要的是,只使用事件处理程序 如果您对它们进行编码,就像这样:

void Grid_MouseMove(object sender, MouseEventArgs e)
{ viewModel.SaveMousePosition(e.GetPosition()); }

你没有违反任何MVVM规则 并且您无法使用命令处理上述事件 MouseMove没有命令(大多数事件都没有),并且您无法在命令中传递事件参数。

您可以使用像this一样的Interaction.Triggers处理每个事件 但是你仍然缺少处理事件参数的能力(并添加丑陋的XAML)。

对我而言,直到WPF支持事件处理程序中的数据绑定,例如

Grid MouseMove="{Binding SaveMousePosition(e)}"

背后的代码仍然是处理事件的最有效方式。

答案 2 :(得分:0)

我遇到了类似的问题,这个问题/答案对我的帮助最大;因此,我将在此处发布我的解决方案,以防其他人稍后使用它对其进行搜索。用mvvm light制成。

我有一个自定义的winforms控件作为模型,有一个WPF控件作为视图。因此,View的xaml(我的View有一个用户控件,没有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放大(这是我的模型实现的地方)

然后,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类,这可能很糟糕,但至少可以正常工作。