WPF: параметр команды для команды удаления в списке - PullRequest
4 голосов
/ 13 августа 2010

В моей модели представления у меня есть список (ObservableCollection), содержащий элементы.В представлении этот список отображается в виде ItemsControl.В каждом ряду есть кнопка «Удалить».Я хочу, чтобы команда позади кнопки удаляла элемент из списка.

<ItemsControl ItemsSource="{Binding myList}">
    <ItemsControl.ItemTemplate>
        ...
            <Button Command="{StaticResource myDeleteCommand}" CommandParameter="???">
                Remove item
            </Button>
        ...
    </ItemsControl.ItemTemplate>
</ItemsControl>

Что передать в качестве параметра команды?

  • Сам элемент (Binding .)?Тогда у меня нет ссылки на список в команде, поэтому мне нужно изменить свою модель так, чтобы каждый элемент списка содержал обратную ссылку на список.
  • Список?Тогда у меня нет ссылки на предмет.
  • Оба?Затем мне нужно написать MultiConverter, который переводит список плюс элемент в какой-то пользовательский объект.Похоже, это слишком много для такой простой задачи.

Есть идеи?Мне кажется, что это довольно распространенный сценарий, поэтому я думаю, что должно быть какое-то хорошо зарекомендовавшее себя решение для наилучшей практики ...

Ответы [ 2 ]

4 голосов
/ 13 августа 2010

Во-первых, я бы обработал команду во ViewModel. Я предполагаю, что список, который используется для привязки, находится в ViewModel, поэтому любой код, который «работает» в этом списке, должен также выполняться в ViewModel.

class MyViewModel
{ 
    // ... Clipping rest of ViewModel class ...

    private ObservableCollection<MyObject> mMyList = new ObservableCollection<MyObject>(); 
    private ICommand mMyDeleteCommand;

    public MyViewModel()
    {
        InitializeMyListSomehow();
        mMyDeleteCommand = new MyCommandClass(
            (item) => DeleteItem(item),
            () => mDeleteCanExecute
        );
    }

    public ObservableCollection<MyObject> MyList
    {
        get { return mMyList; }
        set 
        { 
            // Some function that updates the value and implements INPC
            SetProperty("MyList", ref mMyList, value); 
        }
    }

    public ICommand MyDeleteCommand
    {
        get { return mMyDeleteCommand; }
    }

    void DeleteHandler(var item)
    {
        int index = mMyList.Remove(item);
    }


}

Уникальны ли предметы? Если это так, вы можете передать элемент, а обработчик команды Delete может найти этот элемент в списке.

Если предметы не уникальны, вам придется немного поработать над логикой, в зависимости от ожидаемого результата.

Теперь в представлении ваш код будет выглядеть (обратите внимание, что StaticResource становится привязкой):

<ItemsControl ItemsSource="{Binding MyList}">
    <ItemsControl.ItemTemplate>
        ...
            <Button Command="{Binding DataContext.MyDeleteCommand,
                              RelativeSource={RelativeSource FindAncestor,
                                              AncestorType={x:Type ItemsControl}}}" 
                    CommandParameter="{Binding}">
                Remove item
            </Button>
        ...
    </ItemsControl.ItemTemplate>
</ItemsControl>
4 голосов
/ 13 августа 2010

Я реализовал такие команды таким образом, что я передаю Элемент как Параметр.Команда self знает, по какому списку она должна работать.Либо через делегата, который вызывает метод Delete в моем ViewModel, либо команда получает список элементов в своем конструкторе.

, т.е. команда с делегатами

public sealed class SimpleParameterCommandModel<T> : CommandModel
{
    private readonly Action<T> execute;
    private readonly Func<T, bool> canExecute;

    public SimpleParameterCommandModel(string label, string tooltip, Action<T> execute, Func<T, bool> canExecute)
        : base(appCtx, dataCtx, label, tooltip)
    {
        if (execute == null) throw new ArgumentNullException("execute");
        this.execute = execute;
        this.canExecute = canExecute;
    }
    ...
}

использование:

private ICommand _DeleteCommand = null;
public ICommand DeleteCommand
{
    get
    {
        if (_DeleteCommand == null)
        {
            _DeleteCommand = new SimpleParameterCommandModel<IEnumerable<DataObjectModel>>                      ("Delete", "Delete selection from data store", 
                (items) => items.ToList().ForEach(i => DeleteItem(i)),
                (items) => items != null && items.Count() > 0 && AllowDelete);
        }
        return _DeleteCommand;
    }
}
public void DeleteItem(DataObjectModel item)
{
        if (item == null) { throw new ArgumentNullException("item"); }

    myCollection.Remove(item.Object);
}

РЕДАКТИРОВАТЬ: Забыли XAML

<Button Command="{Binding DeleteCommand, ElementName=...}" CommandParameter="{Binding}">
        Remove item
</Button>
...