Partage
  • Partager sur Facebook
  • Partager sur Twitter

[WPF] Command et portée de définition

Comment accèder plus rapidement à une Command ?

Sujet résolu
Anonyme
    5 février 2012 à 10:05:55

    Bonjour,

    Je viens de découvrir les Command de WPF grâce à ces deux pages :

    Dans celles-ci, on remarque que l'auteur accède aux commandes de sa fenêtre comme ceci :

    <Window.CommandBindings>
      <CommandBinding Command="Help" />
    </Window.CommandBindings>
    


    Cependant, lorsque j'essaye d'accéder à une de mes commandes de cette manière, cela ne fonctionne pas vraiment :

    Image utilisateur

    Conversion de CommandConverter impossible à partir de System.String


    Je suis obligé de passer par un Command="{x:Static my:BlockEditorWindow.SaveCommand}" pour que cela fonctionne, cependant j'aimerai savoir comment l'auteur a été en mesure d'éviter d'utiliser cette méthode fastidieuse.
    Pourtant, j'ai bien implémenté this.DataContext = this; dans le constructeur de ma fenêtre et voici comment est déclarée la commande au sein du code :

    public static RoutedCommand SaveCommand = new RoutedCommand();
    		
    public void SaveCommandExecuted(object sender, ExecutedRoutedEventArgs e)
    {
    	IsFileLoaded = true;
    }
    


    Ce code marche parfaitement bien en utilisant la méthode fastidieuse (j'ai redirigé le clic d'un bouton vers cette commande et le résultat est bien celui attendu).

    Merci d'avance pour votre aide,
    MicroJoe.
    • Partager sur Facebook
    • Partager sur Twitter
      5 février 2012 à 10:12:20

      Je suis loin d'être un expert, mais je peux peut-être t'aider à trouver des pistes pour la solution.

      Dans l'exemple que tu donnes (2e lien) il y a un "<Button Command="Help" Content="Help Command Button" />" dans la fenêtre. As-tu la même chose? Un bouton command?

      Il manque un peu de XAML de ta fenêtre pour que ça soit clair.
      • Partager sur Facebook
      • Partager sur Twitter
      Anonyme
        5 février 2012 à 10:19:46

        Voici le code du Bouton qui marche :

        <Button ContentTemplate="{StaticResource ImagedButtonDataTemplate}" Style="{StaticResource ImagedButtonStyle}"
                DockPanel.Dock="Right"
                Command="{x:Static my:BlockEditorWindow.SaveCommand}">
            <my:ImagedButtonContent Text="Save" Description="Save current block" IconSource="icons/ui/save.png" />
        </Button>
        


        Voici le code du Bouton que j'aimerai faire marcher comme le monsieur :

        <Button ContentTemplate="{StaticResource ImagedButtonDataTemplate}" Style="{StaticResource ImagedButtonStyle}"
                DockPanel.Dock="Right"
                Command="SaveCommand">
            <my:ImagedButtonContent Text="Save" Description="Save current block" IconSource="icons/ui/save.png" />
        </Button>
        
        • Partager sur Facebook
        • Partager sur Twitter
        Anonyme
          5 février 2012 à 10:28:18

          Les Commands, je les utilise avec cette implémentation :
          public class RelayCommand : ICommand
          {
              #region Fields
              private readonly Action<object> _execute;
              private readonly Predicate<object> _canExecute;
              #endregion
          
              #region Constructors
              public RelayCommand( Action<object> execute )
                  : this( execute, null )
              {
              }
          
              public RelayCommand( Action<object> execute, Predicate<object> canExecute )
              {
                  if ( execute == null )
                  {
                      throw new ArgumentNullException( "execute" );
                  }
          
                  this._execute = execute;
                  this._canExecute = canExecute;
              }
              #endregion
          
              #region ICommand Members
              public bool CanExecute( object parameter )
              {
                  return this._canExecute == null ? true : this._canExecute( parameter );
              }
          
              public event EventHandler CanExecuteChanged
              {
                  add { CommandManager.RequerySuggested += value; }
                  remove { CommandManager.RequerySuggested -= value; }
              }
          
              public void Execute( object parameter )
              {
                  this._execute( parameter );
              }
              #endregion
          }
          

          (source : http://msdn.microsoft.com/en-us/magazine/dd419663.aspx )

          Ensuite, tu crées une RelayCommand en arrière-plan. Deux solutions :
          • Soit tu n'utilises la commande que pour un contrôle ; tu peux donc la créer dans le getter :
            public ICommand SaveCommand
            {
                get { return new RelayCommand( SaveCommandExecuted ); }
            }
            
          • Soit tu l'utilises plusieurs fois ; dans ce cas-là, il faut avoir un champ privé :
            private RelayCommand _saveCommand;
            public ICommand SaveCommand
            {
                get
                {
                    if( this._saveCommand == null )
                    {
                        this._saveCommand = new RelayCommand( SaveCommandExecuted );
                    }
                    return this._saveCommand;
                }
            }
            


          Ensuite, il faut créer la méthode SaveCommandExecuted :
          private void SaveCommandExecuted( object parameter )
          {
              Save();
          }
          


          Puis l'utiliser dans le XAML :
          <Button Content="Sauvegarder" Command="{Binding SaveCommand}" />
          


          Tu auras remarqué la présence d'un paramètre object parameter dans la méthode. C'est pour accueillir le CommandParameter :
          <Button Content="Sauvegarder" Command="{Binding SaveCommand}" CommandParameter="{Binding SelectedFile}" />
          


          Mieux encore, il est possible d'utiliser une méthode qui dit si oui ou non la commande peut s'exécuter, spécifiée à la création de la commande :
          // ...
          this._saveCommand = new RelayCommand( SaveCommandExecuted, CanSaveCommandExecute );
          // ...
          
          private void CanSaveCommandExecute( object parameter )
          {
              return this.CurrentFile.HasChanges; // on ne peut pas sauver si on n'a rien modifié
          }
          

          Là aussi il est possible d'utiliser le paramètre.
          • Partager sur Facebook
          • Partager sur Twitter
          Anonyme
            5 février 2012 à 19:22:01

            Il n'y a pas moyen de garder le Command d'origine de WPF ?
            • Partager sur Facebook
            • Partager sur Twitter
            Anonyme
              5 février 2012 à 19:42:07

              Je dois avouer que j'ai jamais essayé d'utiliser les RoutedCommands et RoutedUICommands. Mais vu la doc, c'est pas pratique, faut faire des bindings entre l'objet commande et ses méthodes...
              • Partager sur Facebook
              • Partager sur Twitter
              Anonyme
                5 février 2012 à 21:08:27

                Apparemment, ton RelayCommand ne gère pas les raccourcis clavier, ce qui va déjà être très problématique.

                SaveCommand.InputGestures.Add(new KeyGesture(Key.S , ModifierKeys.Control));
                
                • Partager sur Facebook
                • Partager sur Twitter
                Anonyme
                  5 février 2012 à 21:32:13

                  Faut pas faire ça comme ça...
                  Ajoute des KeyBindings aux contrôles :
                  <TextBox>
                    <TextBox.InputBindings>
                      <KeyBinding Key="Enter" Command="{Binding SendMessageCommand}" />    
                      <KeyBinding Gesture="Ctrl+Tab" Command="{Binding DoSomethingCommand}" />
                    </TextBox.InputBindings>
                  </TextBox>
                  
                  • Partager sur Facebook
                  • Partager sur Twitter
                  Anonyme
                    5 février 2012 à 22:05:47

                    En effet, c'est plus propre et ça marche très bien.
                    Merci !
                    • Partager sur Facebook
                    • Partager sur Twitter

                    [WPF] Command et portée de définition

                    × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                    × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                    • Editeur
                    • Markdown