WPF Commands

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Avalaxy
  • Registratie: Juni 2006
  • Laatst online: 15:43
Ik had er al over gepost in de Devschuur corner, maar er is dus iets wat ik niet begrijp van commands in WPF:

Je maakt een nieuwe class met daarin je commands. In mijn geval heb ik er een RoutedUICommand in die een about box opent. Omdat RoutedUICommand al ICommand implementeert maar verder geen logica heeft in zijn Execute en CanExecute methods moet je die zelf nog gaan implementeren.

Voorbeeld hiervan:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class WindowCommands 
    { 
        private static readonly RoutedUICommand _showAboutBox; 

        static WindowCommands() 
        { 
            _showAboutBox = new RoutedUICommand("About", "About", typeof(WindowCommands)); 
        } 

        public static RoutedUICommand ShowAboutBox 
        { 
            get { return _showAboutBox; } 
        } 
    }



Dan moet je dus een CommandBinding maken die een bepaald command (je RoutedUICommand) mapt aan een 'Executed' method die je dus ergens geprogrammeerd heb. Gewoon een event handler dus?

Voorbeeldje:
XML:
1
2
3
<Window.CommandBindings> 
        <CommandBinding Command="Commands:WindowCommands.ShowAboutBox" Executed="ShowAboutBoxExecuted" /> 
</Window.CommandBindings>


En die ShowAboutBoxExecuted ziet er dan weer zo uit bij mij:
C#:
1
2
3
4
5
6
private void ShowAboutBoxExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            AboutBox aboutBox = new AboutBox();
            aboutBox.Show();
            e.Handled = true;
        }


Maar wat is dan nog het hele punt van die RoutedUICommand, dan kun je toch net zo goed elk menuitem gelijk je event handler aan laten spreken zonder tussenkomst van een RoutedUICommand...? Die event handler kan dan weer een 'Command' uitvoeren in een aparte class zodat je dat ergens gecentralizeerd in je applicatie hebt. Zoals ik het nu heb heb ik gewoon een domme event handler die in mijn MainWindow zit, waar de logica voor dat event ingepropt zit. Maar het is juist het hele punt van een Command om dat juist te voorkomen.

Tevens snap ik niet echt wat je nou aan die Execute() en CanExecute() methods hebt op deze manier?




En nog een bonusvraag die me ineens te binnen schiet: er zijn standaard allerlei Commands zoals Cut, Paste, Open, etc... Echter moet je hier nog wel de logica voor bouwen, of bestaat dat al? Dat heb ik niet echt kunnen vinden...

[ Voor 5% gewijzigd door Avalaxy op 06-03-2011 21:55 ]


Acties:
  • 0 Henk 'm!

Verwijderd

Het mooie aan de WPF commands is dat je de 'Executed' method maar een keer implementeert. De term 'Routed' in RoutedUICommand geeft aan dat deze commands omhoog bubbelen door je Visual Tree totdat ze een command binding tegen komen.

Je hebt nu alleen een menu item waaraan je het command knoopt, maar stel nu eens dat je dezelfde code ook achter een button op een toolbar wilt hebben? Of via een sneltoets? Of via buttons 'gewoon' op je scherm? Het enige wat je dan hoeft te doen is opgeven welk command er afgevuurd moet worden (ShowAboutBox). Deze zal door de visual tree omhoog bubbelen je bestaande command binding gebruiken en presto: geen dubbele code voor het uitvoeren van dezelfde functionaliteit!

Daarnaast hebben controls die met commands om kunnen gaan de mogelijkheid om zichzelf te disablen als het command niet uitgevoerd kan worden (CanExecute geeft false). Deze controle hoef je dus ook maar op een plaats te doen, waarna buttons, toolbars, menu items, etc. disabled of enabled worden op het moment dat dit verandert.

Bonusantwoord: de commands zijn voor je gedefinieerd (je hoeft ze dus niet zoals je ShowAboutCommand apart te maken), maar de command bindings (+ bijbehorende eventhandlers voor de afhandeling) moet je zelf schrijven. Of verwacht je dat .NET voor jou zelfgemaakte applicatie weet hoe er wat waar opgeslagen moet worden? ;)

Acties:
  • 0 Henk 'm!

  • Avalaxy
  • Registratie: Juni 2006
  • Laatst online: 15:43
Dankje voor je antwoord :)

Het is me wel duidelijker geworden wat de WPF implementatie van commands voor toegevoegde waarde hebben. Je zou dus als ik het goed begrijp in je MainWindow alle CommandBindings kunnen definieren en in de code-behind van je MainWindow je event handlers implementeren die iets doen, waarna alle views die ingeladen worden in je MainWindow automatisch gebruik kunnen maken van die commands?

En is het niet makkelijker om de implementatie van je command (dus je event handler) ergens anders (buiten je MainWindow that is) neer te zetten?

Acties:
  • 0 Henk 'm!

  • yade
  • Registratie: Mei 2002
  • Laatst online: 16-07 13:47
Eigenlijk is het niet de bedoeling om code behind te gebruiken maar de view en code te scheiden door middel van het Model View ViewModel design pattern.

Aangezien WPF alleen maar het meest basic fundament biedt voor het gebruik van dit patroon is het raadzaam dit aan te vullen met een framework zoals bijvoorbeeld het MVVM Light Toolkit.

Acties:
  • 0 Henk 'm!

  • beany
  • Registratie: Juni 2001
  • Laatst online: 16:42

beany

Meeheheheheh

Misschien is Caliburn( http://http://caliburn.codeplex.com/ ) ook wel interessant.

Maar het kan ook interessant zijn om je te verdiepen in MVVM. Op google zoeken naar WPF en MVVM levert genoeg leesvoer op :)

Dagelijkse stats bronnen: https://x.com/GeneralStaffUA en https://www.facebook.com/GeneralStaff.ua


Acties:
  • 0 Henk 'm!

  • Avalaxy
  • Registratie: Juni 2006
  • Laatst online: 15:43
Waar halen jullie vandaan dat ik geen MVVM gebruik? :P Dat is namelijk wel het geval.

Acties:
  • 0 Henk 'm!

Verwijderd

Avalaxy schreef op maandag 07 maart 2011 @ 17:02:
Waar halen jullie vandaan dat ik geen MVVM gebruik? :P Dat is namelijk wel het geval.
Omdat je de code-behind gebruikt en dat is niet de bedoeling met MVVM.

Je kunt een ICommand property aanbieden in je viewmodel en dan je Command property binden. Blend 4 heeft mooie designer ondersteuning hiervoor.

Hier zie je hetzelfde advies in je vorige topic: gebruik een MVVM framework. In Prism zit een DelegateCommand die heel mooi ICommand implementeert. Caliburn zal ook een vergelijkbare implementatie hebben. Het wiel is al uitgevonden ;)

/edit
Oh en wat betreft dat venster tonen. Omdat je viewmodel niet afhankelijk hoort te zijn van views, kun je drie dingen doen. Je kunt 1) de notification request van Prism gebruiken, 2) dependency injection om view te laden of 3) een messenger om je view de goede view aan te laten maken. Alledrie mogelijk in Prism.

[ Voor 19% gewijzigd door Verwijderd op 08-03-2011 12:18 ]


Acties:
  • 0 Henk 'm!

  • gehlan
  • Registratie: Maart 2004
  • Laatst online: 13-04-2022
Zoals hier vermeld kun je beste gebruik maken van een goed MVVM framework.

Als je toch graag je huidige aanpak door wil zetten zal je kunnen kijken om zelf een DelegateCommand (iets wat negerzoen ook liet vallen) te implementeren:

Simpel voorbeeld
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class SimpleDelegateCommand : ICommand
{
    Action<object> executeDelegate;
 
    public SimpleDelegateCommand(Action<object> executeDelegate)
    {
        this.executeDelegate = executeDelegate;
    }
 
    public void Execute(object parameter)
    {
        this.executeDelegate(parameter);
    }
 
    public bool CanExecute(object parameter) { return true; }
    public event EventHandler CanExecuteChanged;
}


Vervolgens kun je dan jouw commands op een centrale plek samenstellen (al dan niet static):
C#:
1
2
3
4
5
public class WindowCommands
{
    ICommand showAboutBox = new SimpleDelegateCommand( (x) => new AboutBox().Show(); );
 
    public ICommand ShowAboutBox { get { return showAboutBox; } }


En dan in XAML:

XML:
1
2
3
4
  <Grid.DataContext>
    <local:WindowCommands />
  </Grid.DataContext>
  <Button Command="{Binding ShowAboutBox}">About</Button>


Nogmaals, in diverse MVVM frameworks zitten deze technieken ook al (oa uitgebreider, zoals je ziet returned deze CanExecute altijd true) maar misschien dat je het op een alternatieve methode wil proberen. Heb mijn code btw niet getest :+

Acties:
  • 0 Henk 'm!

  • Avalaxy
  • Registratie: Juni 2006
  • Laatst online: 15:43
Negerzoen en gehlan, bedankt voor jullie antwoorden :) Voor mijn eigen project ben ik inderdaad bezig met het implementeren van DelegateCommands, waarbij ik PRISM als voorbeeld gebruik.

De hoofdreden van mijn vraag is echter dat ik de in de OP genoemde methode uit mijn WPF boek (Pro WPF in C# 2010) heb. De hele manier waarop dat geïmplementeerd werd was mij echter niet duidelijk.

Ik ga er zo weer aan verder, ik hoop dat die DelegateCommands me een beetje duidelijk worden adhv je voorbeelden, bedankt :)
Pagina: 1