Упрощение RelayCommand/DelegateCommand в WPF MVVM ViewModels

Если Вы будете делать MVVM и использовать команды, то Вы будете часто видеть свойства ICommand на ViewModel, которые поддерживаются частными полями RelayCommand или DelegateCommand, как этот пример из исходной статьи MVVM о MSDN:

RelayCommand _saveCommand;
public ICommand SaveCommand
{
    get
    {
        if (_saveCommand == null)
        {
            _saveCommand = new RelayCommand(param => this.Save(),
                param => this.CanSave );
        }
        return _saveCommand;
    }
}

Однако это - большая помеха и устанавливает настройку новые довольно утомительные команды (я работаю с некоторыми старыми разработчиками WinForms, которые передумали относительно всего этого ввода). Таким образом, я хотел упростить его и закопал немного. Я установил точку останова в первой строке получения {} блок и видел, что это только было поражено, когда мое приложение было сначала загружено - я могу позже исчерпать столько команд, сколько я хочу, и эта точка останова никогда не поражается - таким образом, я хотел упростить это для удаления некоторой помехи из моего ViewModels и заметил, что следующий код работает то же:

public ICommand SaveCommand
{
    get
    {
        return new RelayCommand(param => this.Save(), param => this.CanSave );
    }
}

Однако я не знаю достаточно о C# или сборщике "мусора", чтобы знать, могло ли это вызвать проблемы, такие как генерация чрезмерного мусора в некоторых случаях. Это создаст какие-либо проблемы?

19
задан Ben Schoepke 24 June 2010 в 17:03
поделиться

4 ответа

Я обнаружил, что вам нужен оригинальный способ из MSDN, если у вас есть несколько элементов управления, которые вызывают одни и те же команды, иначе каждый элемент управления будет создавать свой собственный RelayCommand. Я не понимал этого, потому что в моем приложении только один элемент управления на команду.

Поэтому, чтобы упростить код в ViewModels, я создам класс-обертку команд, который будет хранить (и лениво инстанцировать) все RelayCommands, и брошу его в мой класс ViewModelBase. Таким образом, пользователям не придется напрямую инстанцировать объекты RelayCommand или DelegateCommand и не нужно будет ничего о них знать:

    /// <summary>
    /// Wrapper for command objects, created for convenience to simplify ViewModel code
    /// </summary>
    /// <author>Ben Schoepke</author>
    public class CommandWrapper
    {
    private readonly List<DelegateCommand<object>> _commands; // cache all commands as needed

    /// <summary>
    /// </summary>
    public CommandWrapper()
    {
        _commands = new List<DelegateCommand<object>>();
    }

    /// <summary>
    /// Returns the ICommand object that contains the given delegates
    /// </summary>
    /// <param name="executeMethod">Defines the method to be called when the command is invoked</param>
    /// <param name="canExecuteMethod">Defines the method that determines whether the command can execute in its current state.
    /// Pass null if the command should always be executed.</param>
    /// <returns>The ICommand object that contains the given delegates</returns>
    /// <author>Ben Schoepke</author>
    public ICommand GetCommand(Action<object> executeMethod, Predicate<object> canExecuteMethod)
    {
        // Search for command in list of commands
        var command = (_commands.Where(
                            cachedCommand => cachedCommand.ExecuteMethod.Equals(executeMethod) &&
                                             cachedCommand.CanExecuteMethod.Equals(canExecuteMethod)))
                                             .FirstOrDefault();

        // If command is found, return it
        if (command != null)
        {
            return command;
        }

        // If command is not found, add it to the list
        command = new DelegateCommand<object>(executeMethod, canExecuteMethod);
        _commands.Add(command);
        return command;
    }
}

Этот класс также лениво инстанцируется классом ViewModelBase, поэтому ViewModels, в которых нет команд, избегут лишних выделений.

8
ответ дан 30 November 2019 в 03:48
поделиться

Это точно так же, как если бы вы предложили свойство - скажем, целое число - которое вычисляет некоторое постоянное значение. Вы можете либо вычислять его при каждом вызове метода get, либо создавать его при первом вызове и затем кэшировать, чтобы возвращать кэшированное значение при последующих вызовах. Таким образом, если getter вызывается не более одного раза, это не имеет никакого значения, если же он вызывается часто, вы потеряете немного (не очень много) производительности, но не получите реальных проблем.

Мне лично нравится сокращать MSDN-путь следующим образом:

RelayCommand _saveCommand;
public ICommand SaveCommand
{
  get
  {
    return _saveCommand ?? (_saveCommand = new RelayCommand(param => this.Save(),
                                                            param => this.CanSave ));
  }
}
17
ответ дан 30 November 2019 в 03:48
поделиться

Единственное, что я делаю, это позволяю Visual Studio печатать за меня.Я только что создал фрагмент кода, который позволяет мне создать RelayCommand, набрав

rc Tab Сохранить Введите

rc - это ярлык фрагмента кода Вкладка загружает текст, который вы вводите, что хотите, и создает все остальные формулировки.

Как только вы посмотрите на один фрагмент кода и создадите свой собственный, вы больше никогда не вернетесь:)

Для получения дополнительной информации о создании фрагментов кода: http://msdn.microsoft.com/en-us/ библиотека / ms165394.aspx

7
ответ дан 30 November 2019 в 03:48
поделиться

Почему бы вам не написать просто:

private readonly RelayCommand _saveCommand = new RelayCommand(param => this.Save(),
                param => this.CanSave );;

public ICommand SaveCommand { get { return _saveCommand; } }
1
ответ дан 30 November 2019 в 03:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: