Вызовите метод после того, как ребенок выполнит команду

1

В настоящее время я изучаю, как реализовать команды в проектах С#/WPF. Предположим, что у меня есть класс MyClass с простой командой MyCommand.

public class MyClass
{
    private RelayCommand _myCommand;
    public ICommand MyCommand
    {
        get
        {
            if (_myCommand == null)
                _myCommand = new RelayCommand(_ => ExecuteMyCommand());
            return _myCommand;
        }
    }

    private void ExecuteMyCommand()
    {
        // Do work...
    }
}

Предположим, теперь я создал ObservableCollection<MyClass> в модели представления, которая привязана к ListView. ListView имеет GridViewColumn с кнопками, привязанными к MyCommand. Все отлично работает.

public class MyViewModel
{
    private ObservableCollection<MyClass> _myCollection;
    public ObservableCollection<MyClass> MyCollection
    {
        get { return _myCollection; }
        set
        {
            _myCollection = value;
            RaisePropertyChanged("MyCollection");
        }
    }

    public void Refresh()
    {
        // Do work to refresh MyCollection to it "live" state
    }
}

Теперь мне нужно вызвать метод Refresh() в модели представления после того, как один из объектов MyCollection выполнит MyCommand, но я не уверен, как подойти к этой ситуации.

Вещи, которые я пробовал:

  • Добавление ссылки на модель представления во время построения MyClass, позволяющее команде вызывать Refresh() через ссылку модели модели при выполнении команды. Это отлично работает, но мне действительно не нравится код - он чувствует себя грязным, когда он ссылается на определенную модель представления, особенно когда она используется в других частях программы.

Вещи, которые я рассмотрел:

  • Изменить Refresh() на метод расширения ObservableCollection<MyClass>, добавив свойство ссылки, как упоминалось ранее, но ссылаясь на ObservableCollection вместо модели представления, которое не будет чувствовать себя грязным, но все же не совсем идеальным в моих глазах...

Каким будет лучший/правильный способ решения этой проблемы?

  • 0
    Я не вижу здесь вопроса ...
  • 0
    @Ben Вопрос был более или менее подразумеваемым «как мне поступить?», Но я добавил еще одну строку только для вас.
Теги:
wpf
mvvm

3 ответа

1
Лучший ответ

Другой способ включить это:

<MenuItem Content="Run MyCommand"
          Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=DataContext.RefreshCommand}"
          CommandParameter="{Binding}"/>

Затем в MyViewModel

public class MyViewModel
{
    private ObservableCollection<MyClass> _myCollection;
    public ObservableCollection<MyClass> MyCollection
    {
        get { return _myCollection; }
        set
        {
            _myCollection = value;
            RaisePropertyChanged("MyCollection");
        }
    }

    //...

    private ICommand _refreshCommand;
    public ICommand RefreshCommand
    {
        get
        {
            if (_refreshCommand== null)
                _refreshCommand= new RelayCommand<MyClass>(p => Refresh(p));
            return _refreshCommand;
        }
    }

    public void Refresh(MyClass parameter)
    {
        if (null == parameter)
            return;
        parameter.ExecuteMyCommand();
        // Do work to refresh MyCollection to it "live" state
    }
}

Примечание. В настоящее время вам не нужно иметь MyCommand для каждого экземпляра MyClass - вы можете передать его в качестве параметра в родительскую модель представления.

Я не могу сказать, что есть правильный способ выполнить вашу задачу. Поэтому я не могу сказать, какой из них лучше.

  • 0
    Мне нравится это решение даже больше, чем мое - я думаю, что команды на самом деле не принадлежат объектам коллекции, потому что класс не должен содержать код, который связан с взаимодействием с представлением, так что это очень хорошо. Кроме того, у каждого объекта не будет собственного экземпляра команды, что, безусловно, хорошо. Я попытаюсь заставить это работать сейчас ...
  • 0
    Работает отлично, спасибо большое! Я переместил все команды из объектов коллекции в модель представления, но оставил методы, которые команды выполняют над объектами. Я очень доволен этим решением!
0

Вы также можете поместить событие click на кнопки (они пузырятся до представления) и вызвать команду из кода

  • 0
    Хотя это и правда, я надеялся отойти от использования событий везде, где их могли заменить команды
0

Мне удалось заставить это работать (я думаю) довольно неплохо.

Прежде всего, я изменил Refresh() на команду. Затем я добавил параметр в метод MyCommand. Метод выполняет свою работу, а затем проверяет параметр, чтобы увидеть, является ли это командой, а затем выполняет ее.

private void ExecuteMyCommand(object param)
{
    // Do work...
    if (param != null && param is ICommand)
        ((ICommand)param).Execute(null);
}

Затем в XAML для представления я устанавливаю CommandParameter в команду, которую я хочу, чтобы она запускалась впоследствии.

<MenuItem Content="Run MyCommand"
          Command="{Binding UploadCommand}"
          CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=DataContext.RefreshCommand}"/>

Если в XAML не указан CommandParameter, он пропускает значение null. Готово...

Ещё вопросы

Сообщество Overcoder
Наверх
Меню