2009-06-26 135 views
9

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

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

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

对于MVVM中事件处理的主题我感到很困惑,所以任何和所有的信息都是值得赞赏的。

回答

4

Josh Smith在MSDN here上写了一篇很好的文章,谈论命令绑定。

在你的情况下,它归结为:

  • 你不会消除所有你的代码隐藏,但它可能会寻找不同的
  • 你CustomObjects可能要有VM垫片类,或者是VM自己利用他描述的RelayCommand体系结构。

HTH。

19

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

是否创建一个CustomObjectViewModel来托管该命令或将该命令放置在具有该列表的同一个ViewModel中真的取决于该动作发生的功能。它是属于CustomObject的东西吗?还是它属于你当前的ViewModel?

或者是有一些种类的结合表达我可以用它来指代回DataContext的窗口有机会获得绑定到视图模型(我键入此,它只是听起来很糟糕,所以我假设对这个想法大“不”)?

这并不像听起来那么糟糕。您并不真的需要窗口的DataContext,只是从切换到单个项目之前的DataContext。所以,如果您的命令是在承载CustomObjects的列表相同视图模型,你可以使用以下两种方法之一绑定到它从内CustomObject的DataTemplate中的一个:

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

另外,我要绑定什么我的命令 为网格控件的 的LeftMouseButtonUp事件。没有“命令” 一个网格,所以我试图使用 InputBindings。

为此,我会使用类似Attached Command Behaviors这将允许您将ICommand附加到任何事件。

1

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

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

    public ICommand MyCommandCommand { get; set; } 

    private void MyCommandExecute() 
    { 
    } 
} 

然后,你必须为你的视图模型作为您的项目列表中的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>