Персонализирани команди в 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
Това наистина е много полезен начин за изпълнение на команди, особено за M-V-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