ItemsControl 中 DataTemplate 上的事件处理程序
Event Handlers on DataTemplate inside ItemsControl
我有一个 ItemsControl
,这样我就可以显示同一模板的多个实例。我需要能够在事件处理程序上执行代码,以便我可以区分控件。
例如:我有一份杂货清单,所以我的 DataTemplate
包含每种食物的 "buy" Button
。我想将所述按钮绑定到代码并告诉按下了哪个按钮。
考虑到我正在使用 MVVM 设计模式
,我怎样才能做到这一点
** XAML :**
<ItemsControl ItemsSource="{Binding MyItemList}">
<ItemsControl.ItemsTemplate>
<DataTemplate>
<Button Content="Buy" />
</DataTemplate>
</ItemsControl.ItemsTemplate>
</ItemsControl>
因此,MyItemList
是一个 List<MyItem>
实例。 DataTemplate
包含修改值或执行 MyItem
中不存在的代码的控件:
我已经阅读了很多关于命令的投标模板的文章,但我找不到使用项目列表的文章。
您可能会做几件事。
<Button Content="Add" Click={Click} Tag="{Binding .}" DataContext="{Binding .}" />
DataContext="{Binding .} - 将整个 VM 实例设置为 属性。您可以对 Tag 属性 执行相同的操作。有时将 Tag 用于这些目的很有用. 你可以使用它们中的任何一个。两者都可以。
public void Click(...)
{
var control = sender as FrameWorkElement;
if(control!= null)
{
var myVM = control.DataContext as MyViewModel;
myVM.DoSomethingWithMyVM();
}
}
您可以创建一个包含网格的用户控件,并在网格中引用自定义用户控件。这是非常灵活的。在它的 ButtonEventhandler 中,您可以访问数据上下文并使用它执行您需要的操作。这要容易得多,但是您将需要更多的工作来处理父对象的通知。如果您想重用此控件,这会更好。
您可以做的另一件事是将按钮的数据上下文设置为整个 ViewModel。最后一个解决方案是将按钮的标签设置为整个 ViewModel。如果您不打算重复使用它,那就更好了。
您也可以将其用作 resourceDictionary 中的资源。
您永远不应在 DataTemplate 中使用事件,这将使您使用强制转换,然后在整个 MVVM 模式中造成漏洞。按钮具有命令 属性,您应该将其 属性 绑定到 MyItem ViewModel 中的命令。
如果您仍然需要使用事件(例如,您不能将 MouseDown 绑定到命令),您应该使用 EventToCommadn 行为,它允许您将事件绑定到命令。你可以在这里阅读:http://msdn.microsoft.com/en-us/magazine/dn237302.aspx
您需要将按钮绑定到 ItemsControl 的 DataContext 的命令。
在 WPF 中搜索命令:(常见实现):
public class RelayCommand<T> : IRelayCommand
{
private Predicate<T> _canExecute;
private Action<T> _execute;
public RelayCommand(Action<T> execute, Predicate<T> canExecute = null)
{
_execute = execute;
_canExecute = canExecute;
}
private void Execute(T parameter)
{
_execute(parameter);
}
private bool CanExecute(T parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public bool CanExecute(object parameter)
{
return parameter == null ? false : CanExecute((T)parameter);
}
public void Execute(object parameter)
{
_execute((T)parameter);
}
public event EventHandler CanExecuteChanged;
public void RaiseCanExecuteChanged()
{
var temp = Volatile.Read(ref CanExecuteChanged);
if (temp != null)
temp(this, new EventArgs());
}
}
在您的 ViewModel 中(ItemsControl 的 DataContext,我希望 :))
private RelayCommand<FoodItem> _addToGroceriesCommand;
public ICommand AddToGroceriesCommand
{
get
{
if (_addToGroceriesCommand == null)
{
_addToGroceriesCommand = new RelayCommand<FoodItem>(OnAddToGroceries);
}
return _addToGroceriesCommand;
}
}
public void OnAddToGroceries(FoodItem newItem)
{
}
XAML :
<ItemsControl ItemsSource="{Binding MyItemList}">
<ItemsControl.ItemsTemplate>
<DataTemplate>
<Button Content="Buy"
Command="{Binding Path=DataContext.AddToGroceriesCommand, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
CommandParameter="{Binding}" />
</DataTemplate>
</ItemsControl.ItemsTemplate>
</ItemsControl>
我有一个 ItemsControl
,这样我就可以显示同一模板的多个实例。我需要能够在事件处理程序上执行代码,以便我可以区分控件。
例如:我有一份杂货清单,所以我的 DataTemplate
包含每种食物的 "buy" Button
。我想将所述按钮绑定到代码并告诉按下了哪个按钮。
考虑到我正在使用 MVVM 设计模式
,我怎样才能做到这一点** XAML :**
<ItemsControl ItemsSource="{Binding MyItemList}">
<ItemsControl.ItemsTemplate>
<DataTemplate>
<Button Content="Buy" />
</DataTemplate>
</ItemsControl.ItemsTemplate>
</ItemsControl>
因此,MyItemList
是一个 List<MyItem>
实例。 DataTemplate
包含修改值或执行 MyItem
中不存在的代码的控件:
我已经阅读了很多关于命令的投标模板的文章,但我找不到使用项目列表的文章。
您可能会做几件事。
<Button Content="Add" Click={Click} Tag="{Binding .}" DataContext="{Binding .}" />
DataContext="{Binding .} - 将整个 VM 实例设置为 属性。您可以对 Tag 属性 执行相同的操作。有时将 Tag 用于这些目的很有用. 你可以使用它们中的任何一个。两者都可以。
public void Click(...)
{
var control = sender as FrameWorkElement;
if(control!= null)
{
var myVM = control.DataContext as MyViewModel;
myVM.DoSomethingWithMyVM();
}
}
您可以创建一个包含网格的用户控件,并在网格中引用自定义用户控件。这是非常灵活的。在它的 ButtonEventhandler 中,您可以访问数据上下文并使用它执行您需要的操作。这要容易得多,但是您将需要更多的工作来处理父对象的通知。如果您想重用此控件,这会更好。
您可以做的另一件事是将按钮的数据上下文设置为整个 ViewModel。最后一个解决方案是将按钮的标签设置为整个 ViewModel。如果您不打算重复使用它,那就更好了。
您也可以将其用作 resourceDictionary 中的资源。
您永远不应在 DataTemplate 中使用事件,这将使您使用强制转换,然后在整个 MVVM 模式中造成漏洞。按钮具有命令 属性,您应该将其 属性 绑定到 MyItem ViewModel 中的命令。
如果您仍然需要使用事件(例如,您不能将 MouseDown 绑定到命令),您应该使用 EventToCommadn 行为,它允许您将事件绑定到命令。你可以在这里阅读:http://msdn.microsoft.com/en-us/magazine/dn237302.aspx
您需要将按钮绑定到 ItemsControl 的 DataContext 的命令。
在 WPF 中搜索命令:(常见实现):
public class RelayCommand<T> : IRelayCommand
{
private Predicate<T> _canExecute;
private Action<T> _execute;
public RelayCommand(Action<T> execute, Predicate<T> canExecute = null)
{
_execute = execute;
_canExecute = canExecute;
}
private void Execute(T parameter)
{
_execute(parameter);
}
private bool CanExecute(T parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public bool CanExecute(object parameter)
{
return parameter == null ? false : CanExecute((T)parameter);
}
public void Execute(object parameter)
{
_execute((T)parameter);
}
public event EventHandler CanExecuteChanged;
public void RaiseCanExecuteChanged()
{
var temp = Volatile.Read(ref CanExecuteChanged);
if (temp != null)
temp(this, new EventArgs());
}
}
在您的 ViewModel 中(ItemsControl 的 DataContext,我希望 :))
private RelayCommand<FoodItem> _addToGroceriesCommand;
public ICommand AddToGroceriesCommand
{
get
{
if (_addToGroceriesCommand == null)
{
_addToGroceriesCommand = new RelayCommand<FoodItem>(OnAddToGroceries);
}
return _addToGroceriesCommand;
}
}
public void OnAddToGroceries(FoodItem newItem)
{
}
XAML :
<ItemsControl ItemsSource="{Binding MyItemList}">
<ItemsControl.ItemsTemplate>
<DataTemplate>
<Button Content="Buy"
Command="{Binding Path=DataContext.AddToGroceriesCommand, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
CommandParameter="{Binding}" />
</DataTemplate>
</ItemsControl.ItemsTemplate>
</ItemsControl>