webentwicklung-frage-antwort-db.com.de

So binden Sie einen Befehl in WPF

Manchmal haben wir komplexe Wege so oft gebraucht, dass wir die einfachsten Wege vergessen haben, die Aufgabe zu erledigen.

Ich weiß, wie man die Befehlsbindung ausführt, aber ich verwende immer denselben Ansatz. 

Erstellen Sie eine Klasse, die die ICommand-Schnittstelle implementiert, und aus dem Ansichtsmodell erstelle ich eine neue Instanz dieser Klasse, und die Bindung funktioniert wie ein Zauber.

Dies ist der Code, den ich für die Befehlsbindung verwendet habe

 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();
    }
}

Aber ich möchte wissen, wie das geht, kein Dritter macht keine neue Klassenerstellung. Führen Sie diese einfache Befehlsbindung mit einer einzelnen Klasse aus. Aktuelle Klasse implementiert von der ICommand-Schnittstelle und erledigt die Arbeit.

13
MegaMind

Prism bereits bereitgestellt Microsoft.Practices.Prism.Commands.DelegateCommand

Ich bin mir nicht sicher, ob es als dritte Partei gilt. Zumindest ist es offiziell und auf MSDN dokumentiert.

Einige eingebaute Befehle wie das Kopieren und Einfügen implementieren die ICommand-Schnittstelle. IMHO es folgt dem Prinzip Öffnen (für Erweiterungen)/Schließen (für Änderungen). damit wir unser eigenes Kommando umsetzen können.


Aktualisieren

Als WPF Commanding dokumentiert hier ein Auszug ...

WPF bietet eine Reihe von vordefinierten Befehlen. wie Cut, BrowseBack und BrowseForward, Play, Stop und Pause.

Wenn die Befehle in den Befehlsbibliotheksklassen Ihren Anforderungen nicht entsprechen, Dann können Sie Ihre eigenen Befehle erstellen. Es gibt zwei Möglichkeiten, eine .__ zu erstellen. benutzerdefinierter Befehl Der erste ist, von Grund auf zu beginnen und .__ umzusetzen. die ICommand-Schnittstelle. Der andere Weg und der allgemeinere Ansatz, dient zum Erstellen eines RoutedCommand oder eines RoutedUICommand .

Ich habe am Anfang ein RoutedCommand-Modell ausprobiert und schließlich ICommand implementiert.

sample XAML-Bindung

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

RoutedCommand unterscheidet sich nicht von RoutedEvent. Dies scheint der 'Clicked'-Ereignishandler einer besseren Schaltfläche zu sein. Es dient dem Zweck: Um die App-Logik von View zu trennen, müssen einige DependencyProperty- oder Code-Behind-Methoden angefügt werden. 

ich persönlich fühle mich wohler mit meiner ICommand.

15
aifarfa

Ich neige dazu, das MVVM Light Framework zu verwenden, das mit einem integrierten RelayCommand geliefert wird. 

Sie fügen Ihrem Ansichtsmodell eine ICommand-Eigenschaft hinzu und weisen ihm dann einen Relaybefehl zu: -

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

In der XAML verwenden Sie einfach die normale Bindung: -

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

Bitte verwenden Sie den Befehl routed, wenn Sie keine neue Klasse erstellen möchten. Hier ist ein kleiner Ausschnitt. Ich habe einen Routing-Befehl als Speichern und Binden an die Befehlsbindung des Fensters erstellt. Erhöhen Sie den Befehl von button.und voila! ..... Ich hoffe, das kann Ihnen helfen 

 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"
  />

 

Ich hoffe, ich habe dein Problem gut verstanden. 

PS: Die Notwendigkeit eines Befehlsentwurfsmusters besteht darin, die Logik der Ausführung und den Aufruf des Befehls zu entkoppeln. Die Befehlsklasse ist eine Möglichkeit, die Logik einzukapseln.

2
paritosh

Wenn Sie davon ausgehen, was Sie tun, ohne den Code in VS auszuführen, besteht Ihr Problem darin, dass Sie InitializeComponent (Rendern von XAML) aufrufen, dann die DataContext setzen, ohne dass sich ein Wert in Ihrer test-Eigenschaft befindet, und schließlich ein privates Member festlegen. Wie soll die Benutzeroberfläche feststellen, dass Ihr Befehl nicht mehr null ist (was der letzte in der Eigenschaft gefundene Wert war)?

Warum nicht instanziieren Sie den Befehl so faul: 

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

Auf diese Weise ist es verfügbar, sobald es erforderlich ist, und Sie benötigen keine Änderungsbenachrichtigung (es sei denn, Sie ändern den Befehl später zur Laufzeit).

Im Übrigen gibt es einige Stellen, an denen Sie das Gefühl haben, dass im Befehls-Bindungsszenario kein Code ausgeführt wird: 

1) CanExecute () gibt "false" zurück: Geben Sie einfach "true" zurück oder bewerten Sie es entsprechend Ihrem Geschäftsfall.

2) Die Bedingungen von CanExecute ändern sich, sodass true zurückgegeben wird, es wird jedoch nicht aufgerufen: Sie können Ihren Command mit der CommandManager-Klasse verbinden, siehe here . Stellen Sie sicher, dass 1) gelöst ist, bevor Sie dies versuchen. Dadurch wird sichergestellt, dass Ihre Benutzeroberfläche häufig CanExecute erneut abfragt, und wenn dies noch nicht ausreicht, rufen Sie die Methode CommandManager.InvalidateRequerySuggested() explizit auf.

3) Ihre Bindung ist falsch. Ändern Sie den Bindungscode wie folgt:

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

Dadurch wird Ihr Ausgabefenster immer dann angezeigt, wenn der Wert der Bindung gezogen oder gedrückt wird. Achten Sie auf den Begriff "Endwert verwenden". Wenn es null ist, ist Ihr Befehl nicht dort, wo er (noch) sein soll.

1

Nun, du hast es fast geschafft. Stellen Sie nur sicher, dass CanExecute () true zurückgibt, andernfalls wird Ihr Code nicht ausgeführt. (Ich denke es wird tatsächlich aber trotzdem). Stellen Sie außerdem sicher, dass "NotifyPropertyChanged ('yourCommand')" hinzugefügt wird 

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

bis hierhin.

Sie können alternativ Test = new MeCOmmand (); DataContext = this;

0

Um eine Tastenkombination zu verknüpfen, fügen Sie im WPF-Fenster-Konstruktor einfach eine Bindung mit einem Delegaten hinzu und verknüpfen Sie sie mit einer Tastaturbewegung.

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)));
   ...
}

Erstellen Sie eine einfache WindowCommand-Klasse, die einen Ausführungsdelegierten benötigt, um alle darauf eingestellten Methoden auszulösen.

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