ItemsControl中的DataTemplate上的事件处理程序

时间:2015-01-19 22:18:39

标签: c# wpf mvvm

我有ItemsControl,因此我可以显示同一模板的多个实例。我需要能够在事件处理程序上执行代码,以便我可以区分控件。

例如:我有一份杂货清单,因此我的DataTemplate包含"购买"每种食物Button。我想将所述按钮绑定到代码并告诉按下了哪个按钮。

考虑到我使用 MVVM设计模式

,我怎样才能做到这一点

** XAML:**

<ItemsControl ItemsSource="{Binding MyItemList}">
     <ItemsControl.ItemsTemplate>
          <DataTemplate>
              <Button Content="Buy" />
          </DataTemplate> 
     </ItemsControl.ItemsTemplate>
</ItemsControl>

因此,MyItemListList<MyItem>个实例。 DataTemplate包含修改值或执行MyItem中不存在的代码的控件:

我已经阅读了很多关于将模板命名为命令的文章,但我找不到一个使用项目列表的文章。

3 个答案:

答案 0 :(得分:4)

您需要将Button绑定到Command的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> 

答案 1 :(得分:3)

你永远不应该在DataTemplates中使用事件,这将使你使用转换然后在整个MVVM模式中打洞。按钮具有Command属性,您应该将该属性绑定到MyItem ViewModel中的命令。

如果你仍然需要使用一个事件(例如你不能将MouseDown绑定到命令),你应该使用EventToCommadn Behavior,它允许你将事件绑定到命令。您可以在此处阅读:http://msdn.microsoft.com/en-us/magazine/dn237302.aspx

答案 2 :(得分:-1)

你可能会做几件事。

<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();
    }
}
  1. 您可以创建包含网格的用户控件,并在网格中引用自定义用户控件。这非常灵活。在它的ButtonEventhandler中,您可以访问datacontext并使用它执行您需要的操作。这样做要容易得多,但是你可以通过parrent对象获得更多的工作。如果要重用此控件,这样会更好。

  2. 您可以做的另一件事是将按钮的datacontext设置为整个ViewModel。最后的努力解决方案是将按钮的标签设置为整个ViewModel。如果您不打算重复使用它,那就更好了。

  3. 您也可以将其用作resourceDictionary的资源。