Пользовательские команды в wpf

Я работаю над приложением WPF, в котором есть панель инструментов / меню, которые можно использовать для нескольких настраиваемых команд. Наверное, около 15-20. Я видел документацию о том, как создавать собственные команды, но ни одна из них не обязательно применима к тому, что я пытаюсь сделать.

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

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

Я также видел использование класса DelegateCommand, но не совсем уверен, хочу ли я двигаться в этом направлении.

Я хотел бы иметь произвольный настраиваемый класс команд, например следующий

public CustomCommand: ICommandd
{
    public bool CanExecute(object parameter)
    {
        //arbitrary logic
    }

    public void Execute(object parameter)
    {

    }
}

Идея состоит в том, что у меня будет 10-20 из них, и я хочу, чтобы они были отделены от всего остального, и чтобы они вызывались при необходимости.

Я знаю, что есть способ разделить свои собственные команды, но не совсем уверен.

Я новичок в использовании команд, поэтому я все еще пытаюсь понять эту концепцию.

Благодарность,


person TheJediCowboy    schedule 19.03.2011    source источник


Ответы (3)


Идея состоит в том, что вы привязываете команду к кнопке, и команда управляет двумя свойствами этой кнопки: «при щелчке» и «включено», в результате чего создается опубликованный вами интерфейс.

Основная причина, по которой вы хотите выполнять команды, - это возможность привязать нажатия кнопок к действиям в вашей модели представления.

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

public class RelayCommand: ICommandd
{
    Action action;
    Func<bool> canExecute;

    public RelayCommand(Action action) : this(action, () => true) {}
    public RelayCommand(Action action, Func<bool> canExecute) 
    { 
        this.action = action; 
        this.canExecute = canExecute;
    }

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

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

Использование в вашей модели представления будет

public RelayCommand SaveCommand { get; set; }

SaveCommand = new RelayCommand(OnSave);

public void Save()
{
    // save logic...
}

Если вы хотите подключить CanExecute, вы также можете использовать второй ctor и предоставить метод CanSave.

public RelayCommand SaveCommand { get; set; }

SaveCommand = new RelayCommand(OnSave, CanSave);

public void Save()
{
    // save logic...
}

public bool CanSave()
{
    return // ... 
}

Как вы могли заметить, в моей реализации я отказался от параметра команды. В большинстве случаев этого будет достаточно, и вы сэкономите дополнительные параметры в методах обработчика. Для оставшихся 10% я реализовал RelayCommand<T>, который принимает действие вместо действия и меняет метод Execute на

    public void Execute(object parameter)
    {
        action((T)parameter);
    }

который требует параметризованного обработчика

SaveCommand = new RelayCommand<SomeType>(OnSave);

public void Save(SomeType toSave)
{
    // save logic using parameter
}

Это избавляет вас от всех проблем с приведением типов, с которыми вы сталкиваетесь при использовании object переменных, и сохраняет безопасность типов ваших моделей представления.

person Zebi    schedule 19.03.2011
comment
Это действительно очень полезный способ выполнения команд, особенно для архитектуры MV-VM, но, к сожалению, это не совсем то, что я ищу, если вы читаете выше, я действительно хочу отделить всю логику от моей точки зрения, У меня есть особые причины для этого, я действительно нашел то, что искал здесь codeproject.com/KB/WPF/ - Тем не менее, проголосуйте за отличный пример, спасибо! - person TheJediCowboy; 20.03.2011
comment
Даже если вы хотите предоставлять свои команды через статический класс, я бы рекомендовал использовать RelayCommands. Таким образом, вам не понадобится код для вашего xaml-файла, а _DeleteContact = new RoutedUICommand("Delete an existing contact", "DeleteContact", typeof(MyAppCommands)); будет содержать жестко закодированные строки, которые могут измениться и помешать рефакторингу. Мне был бы интересен ваш вариант использования. Почему вы хотите поместить все команды в один статический класс? - person Zebi; 21.03.2011

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

Я использую его во всех своих проектах, это реально экономит время.

person Matěj Zábský    schedule 19.03.2011

В итоге я ответил на свой вопрос в следующем сообщении: http://www.codeproject.com/KB/WPF/CentralizingWPFCommands.aspx?display=Print

person TheJediCowboy    schedule 20.03.2011