WPF MVVM - 在ItemsControl内部的命令绑定

时间:2009-06-26 21:39:30

标签: .net wpf mvvm

我目前正在将一个小型WPF项目转换为MVVM。我在ItemsControl绑定的主窗口的ViewModel中有一个List<CustomObject>,并使用DataTemplate构建每个元素的UI。我的旧代码使用DataTemplate中的事件处理程序来处理click事件。我想使用某种命令绑定来消除我的代码隐藏事件处理程序,但我的ItemsControl中项目的DataContext是模型对象,所以我目前无法从ViewModel绑定到ICommand。

所以,我想有几种方法可以解决这个问题,而且我不确定哪种方法可以做到最“MVVM”。我是否将ItemsControl.ItemsSource绑定到表示每个项目的新ViewModel类的集合?或者我使用UserControls而不是DataTemplate然后我可以将每个UserControl绑定到它自己的代表它的ViewModel实例?或者是否有某种绑定表达式我可以用来引用窗口的DataContext来访问绑定到ViewModel(因为我输入它,它听起来很糟糕,所以我假设一个很大的“NO”到这个主意)?

另外,我想将命令绑定到的是Grid控件的LeftMouseButtonUp事件。网格没有“命令”,所以我试图使用InputBindings。我可以使用静态命令(例如内置的ApplicationCommands之一),但是我无法使用绑定表达式绑定到作为ViewModel属性的ICommand实例,因为MouseBinding.Command不是DependencyProperty。

我对MVVM中的事件处理问题非常困惑,所以我们都很感激所有信息。

3 个答案:

答案 0 :(得分:19)

  

我是否将ItemsControl.ItemsSource绑定到代表每个项目的新ViewModel类的集合?

是否创建一个CustomObjectViewModel来托管命令,或者将命令放在具有列表的同一ViewModel中,实际上取决于所发生操作的功能。它是属于CustomObject的东西,还是属于当前ViewModel的东西?

  

或者是否有某种绑定表达式我可以用来引用窗口的DataContext来访问绑定到ViewModel(因为我输入它,它听起来很糟糕,所以我假设一个很大的“NO” “这个想法?”

这并不像听起来那么糟糕。你真的不需要Window的DataContext,只需要在切换到各个项之前的DataContext。因此,如果您的命令位于托管CustomObjects列表的同一ViewModel上,则可以使用以下任一方法从一个CustomObject的DataTemplate中绑定它:

{Binding ElementName=uiCustomObjectsItemsControl, Path=DataContext.MyCommand}
{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ItemsControl}}, Path=DataContext.MyCommand}
  

另外,我想绑定我的命令   to是一个LeftMouseButtonUp事件   网格控制。没有“命令”   一个网格,所以我试图使用   化InputBindings。

为此,我会使用类似Attached Command Behaviors的内容,它可以让您将ICommand附加到任何事件。

答案 1 :(得分:4)

Josh Smith在MSDN here写了一篇很棒的文章,在那里他讨论了命令绑定。

在你的情况下,归结为:

  • 您不会消除所有代码隐藏,但它可能看起来不同
  • 您的CustomObjects可能必须拥有VM填充程序类,或者自己是VM,以利用他描述的RelayCommand体系结构。

HTH。

答案 2 :(得分:1)

您可以尝试将命令保留在模型中。

public class MyModel
{
    public MyModel()
    {
        MyCommand = new DelegateCommand(MyCommandExecute);
    }

    public ICommand MyCommandCommand { get; set; }

    private void MyCommandExecute()
    {
    }
}

然后,您必须为ViewModel中的项目列表设置一个ObservableList,

public class MyViewModel
{
    public MyViewModel()
    {
        MyStarterCommand = new DelegateCommand(MyCommandExecute);

        if (!IsDesignTime)//(bool)DependencyPropertyDescriptor.FromProperty(DesignerProperties.IsInDesignModeProperty, typeof(DependencyObject)).Metadata.DefaultValue;
            MyCommand.Execute(null);
    }

    private ObservableCollection<MyModel> list;
    private  ICommand MyStarterCommand { get; set; }

    public ObservableCollection<MyModel> List
    {
        get { return list; }
        set
        {
            list = value;
            RaisePropertyChanged(() => List);
        }
    }

    private void MyStarterCommandExecute()
    {
        List = new ObservableCollection<MyModel>();

        //Fill the list here
        List.Add(new MyModel());
    }
}

然后在XAML中你必须说;

<ItemsControl ItemsSource="{Binding List}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Button Content="MyButton" Command="{Binding MyCommand}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>