如何在MVVM中处理事件时发送事件处理程序的第二个参数?

时间:2016-03-14 13:23:05

标签: c# wpf xaml mvvm event-handling

我有一个TreeView。使用代码隐藏方法处理事件treeView_Expanded(object sender, RoutedEventArgs e)时,有两个参数TreeViewItem.Expanded

XAML:

<TreeView Name="treeView" TreeViewItem.Expanded="treeView_Expanded"/> 

代码隐藏:

private void treeView_Expanded(object sender, RoutedEventArgs e)
{ 
     //***I take THE SECOND PARAMETER to work ***
     TreeViewItem item = e.Source as TreeViewItem;

}

但是,当我使用MVVM规则处理TreeViewItem.Expanded事件时,我总是使用第一个参数object sender。但我想采用第二个参数RoutedEventArgs e

XAML:

<TreeView ItemsSource="{Binding Person}">
   <i:Interaction.Triggers>
      <helper:RoutedEventTrigger RoutedEvent="TreeViewItem.Expanded">
         <prism:InvokeCommandAction Command="{Binding GetNewTreeViewItemCommand}"/>
      </helper:RoutedEventTrigger>
   </i:Interaction.Triggers>
</TreeView>

视图模型:

public DelegateCommand<RoutedEventArgs> GetNewTreeViewItemCommand { get; set; }
public MainWindowViewModel()
{
   GetNewTreeViewItemCommand = new DelegateCommand<RoutedEventArgs>(LoadNewTreeViewITem);
}

private void LoadNewTreeViewITem(RoutedEventArgs e)
{
   //e is "object sender"(the FIRST parameter), but I want to take  
   //RoutedEventArgs e(the SECOND parameter)             
}           

在MVVM中处理事件时如何发送第二个参数?

1 个答案:

答案 0 :(得分:2)

您可以使用另一个TriggerAction来调用VM中的命令,该命令也会传递args:

<TreeView ItemsSource="{Binding Person}">
  <i:Interaction.Triggers>
     <helper:RoutedEventTrigger RoutedEvent="TreeViewItem.Expanded">
        <local:CustomCommandAction Command="{Binding GetNewTreeViewItemCommand}"/>
     </helper:RoutedEventTrigger>
  </i:Interaction.Triggers>

<强> CustomCommandAction

public sealed class CustomCommandAction : TriggerAction<DependencyObject>
{
    public static readonly DependencyProperty CommandParameterProperty =
        DependencyProperty.Register("CommandParameter", typeof(object), typeof(CustomCommandAction), null);

    public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(
        "Command", typeof(ICommand), typeof(CustomCommandAction), null);

    public ICommand Command
    {
        get
        {
            return (ICommand)this.GetValue(CommandProperty);
        }
        set
        {
            this.SetValue(CommandProperty, value);
        }
    }

    public object CommandParameter
    {
        get
        {
            return this.GetValue(CommandParameterProperty);
        }

        set
        {
            this.SetValue(CommandParameterProperty, value);
        }
    }

    protected override void Invoke(object parameter)
    {
        if (this.AssociatedObject != null)
        {
            ICommand command = this.Command;
            if (command != null)
            {
                if (this.CommandParameter != null)
                {
                    if (command.CanExecute(this.CommandParameter))
                    {
                        command.Execute(this.CommandParameter);
                    }
                }
                else
                {
                    if (command.CanExecute(parameter))
                    {
                        command.Execute(parameter);
                    }
                }
            }
        }
    }
}

<强>更新

XAML

    <TreeView ItemsSource="{Binding Person}" Grid.Row="1" >
        <TreeView.ItemTemplate>
            <HierarchicalDataTemplate ItemsSource="{Binding Children}">
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding Path=Description}" />
                </StackPanel>
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>
        <i:Interaction.Triggers>
            <local:RoutedEventTrigger RoutedEvent="TreeViewItem.Expanded">
                <local:CustomCommandAction Command="{Binding GetNewTreeViewItemCommand}"/>
            </local:RoutedEventTrigger>
        </i:Interaction.Triggers>
    </TreeView>

VM

    private ObservableCollection<Person> _people = new ObservableCollection<Person>();

    public ObservableCollection<Person> Person
    {
        get { return _people; }
    }


    private DelegateCommand _getNewTreeViewItemCommand = null;

    public ICommand GetNewTreeViewItemCommand { get { return _getNewTreeViewItemCommand; } }


    private void LoadNewTreeViewITem(object param)
    {
        var tuple = (Tuple<object, object>)param;

        object sender = tuple.Item1;
        RoutedEventArgs e = tuple.Item2 as RoutedEventArgs;

        System.Diagnostics.Debug.WriteLine(sender);
        System.Diagnostics.Debug.WriteLine(e.RoutedEvent);
    }

    public MainWindowViewModel()
    {
        _getNewTreeViewItemCommand = new DelegateCommand(LoadNewTreeViewITem, (o) => true);

        for (int i = 0; i < 10; i++)
        {
            var newPerson = new Person() { Description = i.ToString() };
            for (int j = 0; j < 10; j++)
            {
                newCode.Children.Add(new Person() { Description = i.ToString() + j.ToString() });
            }

            _people.Add(newCode);
        }
    }

public class Person
{
    public string Description { get; set; }

    public ObservableCollection<Person> Children { get; set; } = new ObservableCollection<Person>();
}

命令

public class DelegateCommand : ICommand
{
    private readonly Action<object> _execute;
    private readonly Func<object, bool> _canExecute;

    public event EventHandler CanExecuteChanged;


    public DelegateCommand(Action<object> execute, Func<object, bool> canExecute)
    {
        _execute = execute;
        _canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        return _canExecute(parameter);
    }

    public void Execute(object parameter)
    {
        _execute(parameter);
    }
}

RoutedEventTrigger

public class RoutedEventTrigger : EventTriggerBase<DependencyObject>
{
    RoutedEvent _routedEvent;

    public RoutedEvent RoutedEvent
    {
        get { return _routedEvent; }
        set { _routedEvent = value; }
    }

    public RoutedEventTrigger()
    {
    }
    protected override void OnAttached()
    {
        Behavior behavior = base.AssociatedObject as Behavior;
        FrameworkElement associatedElement = base.AssociatedObject as FrameworkElement;

        if (behavior != null)
        {
            associatedElement = ((IAttachedObject)behavior).AssociatedObject as FrameworkElement;
        }
        if (associatedElement == null)
        {
            throw new ArgumentException("Routed Event trigger can only be associated to framework elements");
        }
        if (RoutedEvent != null)
        {
            associatedElement.AddHandler(RoutedEvent, new RoutedEventHandler(this.OnRoutedEvent));
        }
    }
    void OnRoutedEvent(object sender, RoutedEventArgs args)
    {
        base.OnEvent(args);
    }
    protected override string GetEventName()
    {
        return RoutedEvent.Name;
    }
}

CustomCommandAction

public sealed class CustomCommandAction : TriggerAction<DependencyObject>
{
    public static readonly DependencyProperty CommandParameterProperty =
        DependencyProperty.Register("CommandParameter", typeof(object), typeof(CustomCommandAction), null);

    public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(
        "Command", typeof(ICommand), typeof(CustomCommandAction), null);

    public ICommand Command
    {
        get
        {
            return (ICommand)this.GetValue(CommandProperty);
        }
        set
        {
            this.SetValue(CommandProperty, value);
        }
    }

    public object CommandParameter
    {
        get
        {
            return this.GetValue(CommandParameterProperty);
        }

        set
        {
            this.SetValue(CommandParameterProperty, value);
        }
    }

    protected override void Invoke(object parameter)
    {
        if (this.AssociatedObject != null)
        {
            ICommand command = this.Command;
            if (command != null)
            {
                if (this.CommandParameter != null)
                {
                    if (command.CanExecute(this.CommandParameter))
                    {
                        command.Execute(this.CommandParameter);
                    }
                }
                else
                {
                    if (command.CanExecute(parameter))
                    {
                        command.Execute(new Tuple<object, object>(this.AssociatedObject, parameter));
                    }
                }
            }
        }
    }
}