Come fare clic programmaticamente su un pulsante in WPF?


144

Poiché non esiste un button.PerformClick()metodo in WPF, esiste un modo per fare clic su un pulsante WPF a livello di codice?

Risposte:


128

WPF adotta un approccio leggermente diverso rispetto a WinForms qui. Invece di avere l'automazione di un oggetto incorporato nell'API, hanno una classe separata per ogni oggetto responsabile dell'automazione. In questo caso è necessario ButtonAutomationPeerper eseguire questa attività.

ButtonAutomationPeer peer = new ButtonAutomationPeer(someButton);
IInvokeProvider invokeProv = peer.GetPattern(PatternInterface.Invoke) as IInvokeProvider;
invokeProv.Invoke();

Ecco un post sul blog sull'argomento.

Nota: l' IInvokeProviderinterfaccia è definita UIAutomationProvidernell'assieme.


2
Slick, non ne ero a conoscenza. Potrebbe essere molto utile per i test automatizzati. Nota che c'è un commento su quel link che suggerisce di usare una factory fornita per ottenere il peer di automazione invece di crearne uno tu stesso.
Greg D,

7
Grazie per questo. Ho faticato a trovare gli spazi dei nomi corretti nella mia app, fino a quando non ho aggiunto un riferimento a UIAutomationProvider. Quindi ho dovuto aggiungereusing System.Windows.Automation.Peers; using System.Windows.Automation.Provider;
sergeantKK il

5
Un one-liner per i propensi:((IInvokeProvider) (new ButtonAutomationPeer(someButton).GetPattern(PatternInterface.Invoke)).Invoke();
Danny Beckett

3
Una cosa da notare è che la chiamata Invoke è asincrona. Ciò significa che se lo si utilizza in un test unitario e la riga successiva è verificare il risultato atteso facendo clic sul pulsante, potrebbe essere necessario attendere.
denver

3
Solo per riferimento, l' IInvokeProviderinterfaccia è definita UIAutomationProvidernell'assieme.
Steven Rands,

188

Come ha detto JaredPar, puoi fare riferimento all'articolo di Josh Smith sull'automazione. Tuttavia, se guardi i commenti al suo articolo, troverai un modo più elegante di raccogliere eventi contro i controlli WPF

someButton.RaiseEvent(new RoutedEventArgs(ButtonBase.ClickEvent));

Personalmente preferisco quello sopra invece dei peer di automazione.


26
La soluzione RaiseEvent genera solo l'evento. Non esegue il comando associato al pulsante (come dice Skanaar)
Eduardo Molteni,

4
Se si utilizza XAML, ad es. <Button Name = "X" Click = "X_Click" />, l'evento verrà intercettato dal gestore al clic come di consueto. +1 da me!
Metao,

4
Sto usando VB ... non sono sicuro che il codice sia diverso per VB contro C #, ma new RoutedEventArgs(Button.ClickEvent)non ha funzionato per me. Ho dovuto usare new RoutedEventArgs(Primitives.ButtonBase.ClickEvent). Altrimenti, funziona alla grande!
BrianVPS,

3
Per elaborare @EduardoMolteni e Skanaar, perdi la funzionalità IsEnabled fornita dai comandi in questo modo, quindi a meno che tu non voglia controllare tutti i tuoi eventi se sono abilitati, AutomationPeer funziona meglio.
Justin Pihony,

34

se vuoi chiamare l'evento click:

SomeButton.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));

E se vuoi che il pulsante appaia premuto:

typeof(Button).GetMethod("set_IsPressed", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(SomeButton, new object[] { true });

e non compresso dopo quello:

typeof(Button).GetMethod("set_IsPressed", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(SomeButton, new object[] { false });

o utilizzare il ToggleButton


22
this.PowerButton.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));

5

Un modo per "fare clic" programmaticamente sul pulsante, se si ha accesso all'origine, è semplicemente chiamare il gestore eventi OnClick del pulsante (o eseguire l'ICommand associato al pulsante, se si stanno facendo le cose nel modo più WPF-y ).

Perché stai facendo questo? Stai eseguendo una sorta di test automatico, ad esempio, o stai provando a eseguire la stessa azione eseguita dal pulsante da una diversa sezione di codice?


Non è l'unica soluzione al mio problema, ma quando ho provato a farlo, ho scoperto che non è facile come button.PerformClick (), quindi solo un po 'curioso ... :)
tghoang

Ho dovuto fare clic sul menu di un'altra finestra nello stesso progetto e MyOtherWindow.mnuEntry_Click (Me, New Windows.RoutedEventArgs) lo ha fatto. Davvero semplice.
Andrea Antonangeli,

4

Come ha detto Greg D , penso che un'alternativa a Automationfare clic su un pulsante usando il modello MVVM (evento click generato e comando eseguito) sia chiamare il OnClickmetodo usando reflection:

typeof(System.Windows.Controls.Primitives.ButtonBase).GetMethod("OnClick", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(button, new object[0]);

Questo è un buon modo per usare un evento da un elemento figlio per lanciare un comando su un genitore.
Cool Blue

2

Quando si utilizza il modello di comando MVVM per la funzione Pulsante (pratica consigliata), un modo semplice per attivare l'effetto del pulsante è il seguente:

someButton.Command.Execute(someButton.CommandParameter);

Questo utilizzerà l' oggetto Command che viene attivato dal pulsante e passa CommandParameter definito da XAML .


Una nota, questo innesca solo l' effetto che il pulsante avrà se cliccato. Non genera eventi di clic nella coda di invio dei messaggi. Per tutti i casi pratici questo è ciò che desidererai ed eviterai eventi di dispatcher non necessari (ad es. Più performanti) ma se in realtà in qualche modo richiedi gli eventi di dispatcher altre soluzioni sopra sono più appropriate
KVKConsultancy

0

Il problema con la soluzione API di automazione è che richiedeva un riferimento all'assembly Framework UIAutomationProvidercome dipendenza progetto / pacchetto.

Un'alternativa è emulare il comportamento. Di seguito è disponibile la mia soluzione estesa che supporta anche il modello MVVM con i suoi comandi associati, implementato come metodo di estensione :

public static class ButtonExtensions
{
    /// <summary>
    /// Performs a click on the button.<br/>
    /// This is the WPF-equivalent of the Windows Forms method "<see cref="M:System.Windows.Forms.Button.PerformClick" />".
    /// <para>This simulates the same behaviours as the button was clicked by the user by keyboard or mouse:<br />
    /// 1. The raising the ClickEvent.<br />
    /// 2.1. Checking that the bound command can be executed, calling <see cref="ICommand.CanExecute" />, if a command is bound.<br />
    /// 2.2. If command can be executed, then the <see cref="ICommand.Execute(object)" /> will be called and the optional bound parameter is p
    /// </para>
    /// </summary>
    /// <param name="sourceButton">The source button.</param>
    /// <exception cref="ArgumentNullException">sourceButton</exception>
    public static void PerformClick(this Button sourceButton)
    {
        // Check parameters
        if (sourceButton == null)
            throw new ArgumentNullException(nameof(sourceButton));

        // 1.) Raise the Click-event
        sourceButton.RaiseEvent(new RoutedEventArgs(System.Windows.Controls.Primitives.ButtonBase.ClickEvent));

        // 2.) Execute the command, if bound and can be executed
        ICommand boundCommand = sourceButton.Command;
        if (boundCommand != null)
        {
            object parameter = sourceButton.CommandParameter;
            if (boundCommand.CanExecute(parameter) == true)
                boundCommand.Execute(parameter);
        }
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.