我目前正在将一个小型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中的事件处理问题非常困惑,所以我们都很感激所有信息。
答案 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写了一篇很棒的文章,在那里他讨论了命令绑定。
在你的情况下,归结为:
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>