web-dev-qa-db-fra.com

Comment lier une commande dans WPF

Parfois, nous utilisions tellement souvent des moyens complexes que nous en oublions les moyens les plus simples.

Je sais comment faire la liaison de commande, mais j'utilise toujours la même approche. 

Créez une classe qui implémente l'interface ICommand et à partir du modèle de vue, créez une nouvelle instance de cette classe et la liaison fonctionne comme un charme.

C'est le code que j'ai utilisé pour la liaison de commande

 public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;            
        testCommand = new MeCommand(processor);
    }

    ICommand testCommand;

    public ICommand test
    {
        get { return testCommand; }
    }
    public void processor()
    {
        MessageBox.Show("hello world");
    }
}

public class MeCommand : ICommand
{
    public delegate void ExecuteMethod();
    private ExecuteMethod meth;
    public MeCommand(ExecuteMethod exec)
    {
        meth = exec;
    }

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

    public event EventHandler CanExecuteChanged;

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

Mais je veux connaître le moyen de base pour faire cela, pas de tierce partie, ni de nouvelle création de classe. Faites cette liaison de commande simple en utilisant une seule classe. La classe réelle implémente à partir de l'interface ICommand et fait le travail.

13
MegaMind

Prism déjà fourni Microsoft.Practices.Prism.Commands.DelegateCommand

Je ne suis pas sûr que ce soit considéré comme une 3ème partie. Au moins, c'est officiel et documenté sur MSDN.

Certaines commandes natives telles que copier/coller implémentent l'interface ICommand. IMHO le suivant le principe Open (pour extend)/Close (pour modifications). afin que nous puissions mettre en œuvre notre propre commande.


Mettre à jour

Comme WPF Commandant a documenté ici , un extrait ...

WPF fournit un ensemble de commandes prédéfinies. tels que Cut, BrowseBack et BrowseForward, Lecture, Arrêt et Pause.

Si les commandes dans les classes de la bibliothèque de commandes ne répondent pas à vos besoins, alors vous pouvez créer vos propres commandes. Il y a deux façons de créer un commande personnalisée. La première consiste à partir de la base et à mettre en œuvre l'interface ICommand. L’autre manière et l’approche plus courante, est de créer un RoutedCommand ou un RoutedUICommand .

J'ai essayé le modèle RoutedCommand au début et j'ai fini par implémenter ICommand.

exemple de liaison XAML

<CommandBinding Command="{x:Static custom:Window1.CustomRoutedCommand}"
                    Executed="ExecutedCustomCommand"
                    CanExecute="CanExecuteCustomCommand" />

RoutedCommand n'est pas différent de RoutedEvent. cela semble être le meilleur gestionnaire d'événements 'Clicked' d'un bouton. Son objectif est le suivant: séparer la logique d’application de View, mais en exiger quelques-uns, associez DependencyProperty ou code-behind. 

personnellement, je me sens plus à l'aise avec la mise en œuvre de mon ICommand.

15
aifarfa

J'ai tendance à utiliser le framework MVVM light qui est livré avec un RelayCommand intégré. 

Vous ajoutez une propriété ICommand à votre modèle de vue, puis vous lui affectez une relaycommand: -

ICommand ClickMeCommand {get;set;}
private void InitCommands()
{
   ClickMeCommand = new RelayCommand(()=>HasBeenClicked=true);
   //or
   ClickMeCommand = new RelayCommand(ClickMeEvent);
}
public void ClickMeEvent()
{
   HasBeenClicked=true;
}

Dans le xaml, vous utilisez simplement la liaison normale: -

<Button Content='Push me' Command='{Binding ClickMeCommand}' />
3
Ross Dargan

Veuillez utiliser la commande routée si vous ne voulez pas créer de nouvelle classe. voici un petit extrait. J'ai créé une commande routée en tant que Enregistrer et le lie à la commande Liaison de la fenêtre, relance la commande depuis button.and le tour est joué! ..... J'espère que cela peut vous aider 

 public partial class Window1 : Window
 {
    public static readonly RoutedCommand Foo = new RoutedCommand();

    public Window1()
    {
        InitializeComponent();
    }

    void Foo_CanExecute(object sender, CanExecuteRoutedEventArgs e)
    {
        // The Window gets to determine if the Foo 
        // command can execute at this time.
        e.CanExecute = true;
    }

    void Foo_Executed(object sender, ExecutedRoutedEventArgs e)
    {
        // The Window executes the command logic when the user wants to Foo.
        MessageBox.Show("The Window is Fooing...");
    }
}

 <Window.CommandBindings>
 <CommandBinding
  Command="{x:Static  local:Window1.Foo}"
  CanExecute="Foo_CanExecute"
  Executed="Foo_Executed"
  />

 

J'espère avoir bien compris votre problème. 

PS: Le besoin de modèle de conception de commande est de découpler la logique d’exécution et d’appeler de commande.So La classe de commande est un moyen d’encapsuler la logique.

2
paritosh

À en juger par ce que vous faites sans exécuter le code dans VS, votre problème est que vous appelez InitializeComponent (render XAML), puis définissez la DataContext sans aucune valeur dans votre propriété test et définissez enfin un membre privé. Comment l'interface utilisateur est-elle censée remarquer que votre commande n'est plus nulle (quelle était la dernière valeur trouvée dans la propriété)?

Pourquoi ne pas instancier la commande paresseusement comme ceci: 

public ICommand test
{
    get
    { 
      if(testCommand== null)
      {
         testCommand= new MeCommand(processor);
       }
      return testCommand; 
    }
}

De cette manière, il sera disponible dès que nécessaire et vous n’aurez pas besoin de la notification de modification (à moins que vous ne changiez cette commande ultérieurement au moment de l’exécution).

En passant, il y a quelques endroits où vous avez l'impression qu'aucun code n'est exécuté dans le scénario de liaison de commande: 

1) CanExecute () renvoie false: il suffit de renvoyer true ou d’évaluer en fonction de votre analyse de rentabilité.

2) Les conditions de CanExecute changent pour qu'il renvoie true, mais il n'est pas appelé: vous pouvez connecter votre commande à la classe CommandManager, voir ici . Assurez-vous que 1) est résolu avant d'essayer cela. Cela garantit que votre interface utilisateur va actualiser la CanExecute assez fréquemment, et si cela ne suffit toujours pas, appelez explicitement la méthode CommandManager.InvalidateRequerySuggested().

3) Votre liaison est incorrecte. Modifiez le code de liaison comme suit:

Command="{Binding Path=test, PresentationTraceSources.TraceLevel=High}"

Cela spammera votre fenêtre de sortie chaque fois que la valeur de la liaison sera tirée ou poussée. Cherchez le terme "utiliser la valeur finale". Si elle est nulle, votre commande n'est pas là où elle est supposée être (pour le moment).

1
Sebastian Edelmeier

Eh bien, vous l'avez presque. Assurez-vous simplement que CanExecute () retournera true, sinon votre code ne sera pas exécuté. (Je pense que ce sera le cas, mais quand même) Assurez-vous également que vous ajoutez "NotifyPropertyChanged ('votreCommand')" à 

   public ICommand test
    {
        get { return testCommand; }
        set { testCOmmand = value; NotifyPropertyChanged("test"); }
    }

jusqu'ici.

Vous pouvez également faire Test = new MeCOmmand (); DataContext = this;

0
Erti-Chris Eelmaa

Dans le constructeur de la fenêtre WPF, pour lier un raccourci clavier, ajoutez simplement une liaison avec un délégué et associez-le à un geste clé.

public YourWindow() //your constructor
{
   ...
   //bind keyboard command shortcuts
   InputBindings.Add(new KeyBinding( //add a new key-binding, bind it to your command object which takes a delegate
      new WindowCommand(this)
      {
         ExecuteDelegate = TogglePause //REPLACE TogglePause with your method delegate
      }, new KeyGesture(Key.P, ModifierKeys.Control)));
   ...
}

Créez une classe WindowCommand simple qui oblige un délégué à exécuter toute méthode définie sur celle-ci.

public class WindowCommand : ICommand
{
    private MainWindow _window;
    public Action ExecuteDelegate { get; set; }

    public WindowCommand(MainWindow window)
    {
        _window = window;
    }

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

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        if (ExecuteDelegate != null)
        {
            ExecuteDelegate();
        }
        else
        {
            throw new InvalidOperationException();
        }
    }
}
0
Ayo I