CommandParameter события триггера с использованием InvokeDelegateCommandAction - PullRequest
1 голос
/ 20 июня 2011

Я использую класс InvokeDelegateCommandAction из блог Алексея Захарова на основе некоторых советов от парней, что это лучший способ отправить параметр из View в ViewModel из EventTrigger.

Вот что у меня есть.

В представлении (точнее, в DataGrid):

<i:Interaction.Triggers>
    <i:EventTrigger EventName="SelectionChanged" >
        <cmnwin:InvokeDelegateCommandAction 
                Command="{Binding SelectedExcludedItemChangedCommand}"
                CommandParameter="{Binding RelativeSource={RelativeSource self}, Path=SelectedItems}" />
    </i:EventTrigger>
</i:Interaction.Triggers>

В модели представления:

public DelegateCommandWithParameter SelectedActiveItemChangedCommand
{
    get
    {
        return selectedActiveItemChangedCommand ??
            (selectedActiveItemChangedCommand = new DelegateCommandWithParameter(DoSelectedActiveItemsChanged, CanDoSelectedActiveItemsChanged));
    }
}

public bool CanDoSelectedActiveItemsChanged(object param)
{
    return true;
}

public void DoSelectedActiveItemsChanged(object param)
{
    if (param != null && param is List<Object>)
    {
        var List = param as List<Object>;
        MyLocalField = List;
    }
}

Новый видDelegateCommand, который позволяет мне передавать объекты как аргументы:

public class DelegateCommandWithParameter : ICommand
{
    #region Private Fields
    private Func<object, bool> canExecute;
    private Action<object> executeAction;
    private bool canExecuteCache;
    #endregion

    #region Constructor
    public DelegateCommandWithParameter(Action<object> executeAction, Func<object, bool> canExecute)
    {
        this.executeAction = executeAction;
        this.canExecute = canExecute;
    }
    #endregion

    #region ICommand Members
    public bool CanExecute(object parameter)
    {
        bool temp = canExecute(parameter);
        if (canExecuteCache != temp)
        {
            canExecuteCache = temp;
            if (CanExecuteChanged != null)
            {
                CanExecuteChanged(this, new EventArgs());
            }
        }
        return canExecuteCache;
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        executeAction(parameter);
    }
    #endregion
}

Всякий раз, когда мой код попадает в DoSelectedActiveItemsChanged, аргумент всегда равен NULL .... я здесь полная глупость?Где CommandParamter связан с аргументами команды?AKA, почему View ничего не передает команде?Пожалуйста, помогите.

Ответы [ 2 ]

3 голосов
/ 20 июня 2011

Я сделал это с ListBox, но получил то же самое. Следующее хорошо, так как оно передает CommandParameter вместо параметра invoke. Так почему же CommandParameter null?

protected override void Invoke( object parameter ) {
    this.InvokeParameter = parameter;

    if ( this.AssociatedObject != null ) {
        ICommand command = this.ResolveCommand();
        if ( ( command != null ) && command.CanExecute( this.CommandParameter ) ) {
            command.Execute( this.CommandParameter );
        }
    }
}

CommandParameter не работает должным образом, потому что ваша привязка устанавливает его на null. {RelativeSource Self} разрешается до InvokeDelegateCommandAction, и у него нет свойства SelectedItems. Вместо этого используйте эту привязку:

CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListBox}}, Path=SelectedItems}"

Тогда CommandParameter перейдет в SelectedItemCollection из ListBox.

Есть еще одна проблема, которую вы быстро обнаружите. DoSelectedActiveItemsChanged() param будет экземпляром SelectedItemCollection, а не List<Object>.

1 голос
/ 21 июня 2011

Я решил проблему с помощью наблюдений Джоэла ... Для тех, кто может быть заинтересован, вот как. Хотя, очевидно, я по праву приписал Джоэлу правильный ответ, представляется правильным поместить эту информацию в качестве ответа, а не редактирования вопроса.

Я обнаружил универсальный DelegateCommand, поэтому избавился от DelegateCommandWithParameter

public ICommand SelectedObjectsChangedCommand 
{
    get
    {
        return selectedObjectsChangedCommand ??
            (selectedObjectsChangedCommand = new DelegateCommand<MyType>(DoSelectedObjectsChangedCommand , CanDoSelectedObjectsChangedCommand ));
    }
}

Теперь 'Do' (метод Execute) с возвращением SelectionChangedEventArgs ...

public void DoSelectedObjectsChangedCommand(object param)
{
    if (param != null && param is SelectionChangedEventArgs)
    {
        foreach (MyType object in ((SelectionChangedEventArgs)param).AddedItems.Cast<MyType>().ToList())
        {
            selectedObjects.Add(object);
        }
        foreach (MyType object in ((SelectionChangedEventArgs)param).RemovedItems.Cast<MyType>().ToList())
        {
            selectedObjects.Remove(object);
        }
        UpdateAllCanDos();
    }
} 

Наряду с остальной частью моей бизнес-логики это обеспечивает очень плавный и интуитивно понятный пользовательский интерфейс. Большое спасибо всем ответчикам. Я работаю над WPF и MVVM с NHibernate не только месяц, и я не могу не признать, что SO-сообщество помогает мне преодолеть кривые обучения наилучшим и наиболее полезным способом.

...