How to programmatically click a button in WPF?

242

Solution 1

WPF takes a slightly different approach than WinForms here. Instead of having the automation of a object built into the API, they have a separate class for each object that is responsible for automating it. In this case you need the ButtonAutomationPeer to accomplish this task.

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

Here is a blog post on the subject.

Note: IInvokeProvider interface is defined in the UIAutomationProvider assembly.

Solution 2

Like JaredPar said you can refer to Josh Smith's article towards Automation. However if you look through comments to his article you will find more elegant way of raising events against WPF controls

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

I personally prefer the one above instead of automation peers.

Solution 3

if you want to call click event:

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

And if you want the button looks like it is pressed:

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

and unpressed after that:

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

or use the ToggleButton

Solution 4

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

Solution 5

One way to programmatically "click" the button, if you have access to the source, is to simply call the button's OnClick event handler (or Execute the ICommand associated with the button, if you're doing things in the more WPF-y manner).

Why are you doing this? Are you doing some sort of automated testing, for example, or trying to perform the same action that the button performs from a different section of code?

Share:
242

Related videos on Youtube

soldy
Author by

soldy

Updated on August 22, 2021

Comments

  • soldy
    soldy over 2 years

    What is the correct way to extend build-in components of MaterialUI v5? What I'd like to do:

    1. Style the build-in component
    2. Make a wrapper on top of my styled component with additional components

    The current code:

    import {Box, Link, LinkProps} from '@mui/material';
    import {styled} from '@mui/material/styles';
    
    const StyledLink = styled(Link)<LinkProps>({
      display: 'flex',
      flexDirection: 'column',
      alignItems: 'center',
      color: '#6b7688',
      fontWeight: 500,
      fontSize: '12.8px',
      textTransform: 'uppercase',
      textDecoration: 'none',
    
      '&:hover, &.Mui-focusVisible': {
        color: '#313bac',
        transition: 'all 0.3s ease-in-out',
    
        // LinkHoverElement
        '& .MuiBox-root': {
          backgroundColor: '#313bac',
        },
      },
    });
    
    const LinkHoverElement = styled(Box)({
      width: '5px',
      height: '5px',
      marginBottom: '5px',
      borderRadius: '50%',
      backgroundColor: 'transparent',
    });
    
    const MenuLink = ({children, ...restProps}: LinkProps) => {
      return (
        <StyledLink {...restProps}>
          <LinkHoverElement />
          {children}
        </StyledLink>
      );
    };
    
    export default MenuLink;
    

    It works, I also may use all props ('sx' prop as well)

    <MenuLink
      sx={{mx: '1rem'}}
      key={page}
      href={`#${page}`}>
      {page}
    </MenuLink>
    

    seems like a 'god object', I've read documentation and uses this articles:

    1. Reusable component
    2. styled()

    but haven't found an complicated example and feel like the code above isn't a best practice

    The codesandbox example

  • tghoang
    tghoang about 15 years
    It's not the only solution to my problem, but when I tried to do this, I found that it's not as easy as button.PerformClick(), so just a bit curious... :)
  • Greg D
    Greg D about 15 years
    Slick, I wasn't aware of this. Could be very useful for automated testing. Note that there's a comment on that link which suggests using a provided factory to get the automation peer instead of creating one yourself.
  • Eduardo Molteni
    Eduardo Molteni over 14 years
    The RaiseEvent solution only raises the event. It does not execute the Command associated with the Button (as Skanaar say)
  • Phil Green
    Phil Green almost 14 years
    If you use XAML eg <Button Name="X" Click="X_Click" />, the event will be caught by the on click handler as per normal. +1 from me!
  • Mageician
    Mageician about 12 years
    I'm using VB...not sure if the code is different for VB verses C#, but new RoutedEventArgs(Button.ClickEvent) didn't work for me. I had to use new RoutedEventArgs(Primitives.ButtonBase.ClickEvent). Otherwise, works great!
  • Justin Pihony
    Justin Pihony almost 12 years
    To elaborate on @EduardoMolteni and Skanaar, you lose the IsEnabled functionality given by Commands this way, so unless you want all of your events to check if they are enabled, the AutomationPeer works better.
  • robi-y
    robi-y about 11 years
    If this is a ToggleButton: button.IsChecekd = false/true; seems to be enough
  • MEMark
    MEMark over 10 years
    I would change the second line to IInvokeProvider invokeProv = (IInvokeProvider)peer.GetPattern( PatternInterface.Invoke ); since you know that this cast should always be valid.
  • sergeantKK
    sergeantKK over 9 years
    Thanks for this. I struggled to find the correct namespaces in my app, until I added a reference to UIAutomationProvider. Then had to add using System.Windows.Automation.Peers; using System.Windows.Automation.Provider;
  • Danny Beckett
    Danny Beckett over 9 years
    A one-liner for the inclined: ((IInvokeProvider) (new ButtonAutomationPeer(someButton).GetPattern(PatternInterface‌​.Invoke)).Invoke();
  • denver
    denver about 9 years
    One thing to note is that the Invoke call is asynchronous. That means if you are using it in a unit test and your next line is to check the expected result of clicking the button, you might have to wait.
  • Cool Blue
    Cool Blue over 7 years
    This is a good way to use an event from a child element to fire a command on a parent.
  • Steven Rands
    Steven Rands over 7 years
    Just for reference, the IInvokeProvider interface is defined in the UIAutomationProvider assembly.
  • Andrea Antonangeli
    Andrea Antonangeli almost 7 years
    I had to click on the menu of another window in the same project, and MyOtherWindow.mnuEntry_Click(Me, New Windows.RoutedEventArgs) did it. Really simple.
  • KVKConsultancy
    KVKConsultancy over 5 years
    One note, this only triggers the effect the button will have if clicked. It does not generate any click events in the message dispatching queue. For all practical cases this is what you will desire and will avoid unnecessary dispatcher events (e.g. more performant) but if your actually somehow requiring the dispatcher events other solutions above are more appropriate
  • Hassaan Raza
    Hassaan Raza almost 4 years
    what does some button reffers to?
  • Zhong W
    Zhong W over 3 years
    It saves my day.