Silverlight default button trigger

February 9, 2010 at 6:39 PMdsoltesz

Lots of time when a user is on a page or entering text in a textbox and presses the enter key, you want a default button to be invoked automatically.  A common scenario would be on a search page.  When a user presses the enter key in a textbox, you want the search button to be invoked automatically. You could handle the keydown event of each and every textbox or you could create a trigger that you just attach to the textbox. 

I decided to create a trigger that can be attached to any control.

    public class DefaultEnterButtonTrigger : TargetedTriggerAction<ButtonBase>

    {

        /// <summary>

        /// Gets or sets the peer.

        /// </summary>

        /// <value>The peer.</value>

        private AutomationPeer _peer { get; set; }

 

        /// <summary>

        /// Gets or sets the target button

        /// </summary>

        private ButtonBase _targetedButton { get; set; }

 

        /// <summary>

        /// Called after the TargetedTriggerAction is attached to an AssociatedObject.

        /// </summary>

        /// <remarks>Override this to hook up functionality to the AssociatedObject.</remarks>

        protected override void OnAttached()

        {

            base.OnAttached();

            _targetedButton = this.Target;

            if (null == _targetedButton)

            {

                return;

            }

 

            // set peer

            this._peer = FrameworkElementAutomationPeer.FromElement(_targetedButton);

            if (this._peer == null)

            {

                this._peer = FrameworkElementAutomationPeer.CreatePeerForElement(_targetedButton);

            }

        }

 

        /// <summary>

        /// Called after targeted Button change.

        /// </summary>

        /// <remarks>Override this to hook up functionality to the new targeted Button.</remarks>

        protected override void OnTargetChanged(ButtonBase oldTarget, ButtonBase newTarget)

        {

            base.OnTargetChanged(oldTarget, newTarget);

            _targetedButton = newTarget;

            if (null == _targetedButton)

            {

                return;

            }

 

            // set peer

            this._peer = FrameworkElementAutomationPeer.FromElement(_targetedButton);

            if (this._peer == null)

            {

                this._peer = FrameworkElementAutomationPeer.CreatePeerForElement(_targetedButton);

            }

        }

 

        /// <summary>

        /// Invokes the targeted Button when Enter key is pressed inside Control.

        /// </summary>

        /// <param name="parameter">KeyEventArgs with Enter key</param>

        protected override void Invoke(object parameter)

        {

            KeyEventArgs keyEventArgs = parameter as KeyEventArgs;

            if (null != keyEventArgs && keyEventArgs.Key == Key.Enter)

            {

                if (null != _peer && _peer.IsEnabled())

                {

                    IInvokeProvider invokeProvider = _peer.GetPattern(PatternInterface.Invoke) as IInvokeProvider;

                    invokeProvider.Invoke();

                }

            }

        }

    }

 

Now to use the trigger you need to add a reference to the System.Windows.Interactivity.dll

In your xaml filed add

xmlns

 

:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

and add your trigger

xmlns:triggers="clr-namespace:MyApp.Triggers;assembly=MyApp"  //your trigger that you created above

Now add a textbox and a button to your xaml page

<TextBox x:Name="myTextBox >

  <i:Interaction.Triggers>

    <i:EventTrigger EventName="KeyDown" >

     <triggors:DefaultEnterButtonBehavior TargetName="SearchButton" />

    </i:EventTrigger>

  </i:Interaction.Triggers>

</TextBox>

<Button x:Name="SearchButton" Content="Search" Click="SearchButton_Click" />

Run your app and when your press the enter button from with in your textbox, your search button will be invoked. 

Posted in: c# | silverlight

Tags: , , , , ,

Comments (7) -

Dan,
Great post.

I'm having an issue in SL(MVVM) that the model does not get updated because I guess the textbox does not really loose focus when the button is invoked.

Any ideas of how to first set the focus to the button? Not sure if that will help or not, but is what I'm looking into doing.
thanks.

Reply

Voss, you can set focus to button by calling YourButton.Focus();

Reply

Paul Jesus Sanchez
Mexico Paul Jesus Sanchez says:

Great post!

Voss, I was having the same problem, but fixed like this:

protected override void Invoke(object parameter)
        {
            KeyEventArgs keyEventArgs = parameter as KeyEventArgs;
            
            if (null != keyEventArgs && keyEventArgs.Key == Key.Enter)
            {
                if (null != _peer && _peer.IsEnabled())
                {
                    IInvokeProvider invokeProvider = _peer.GetPattern(PatternInterface.Invoke) as IInvokeProvider;
                    //PJS: In order to properly work MVVM, we have to lost the focust of the textbox first to update de associated property value.
                    ((Button)((System.Windows.Automation.Peers.FrameworkElementAutomationPeer)(invokeProvider)).Owner).GotFocus += new RoutedEventHandler(DefaultEnterButtonTrigger_GotFocus);
                    ((Button)((System.Windows.Automation.Peers.FrameworkElementAutomationPeer)(invokeProvider)).Owner).Focus();
                    
                    //invokeProvider.Invoke();
                }
            }
        }


When the textbox focus is lost and the MVVM property is updated, then we can invoke the button's action

private void DefaultEnterButtonTrigger_GotFocus(object sender, RoutedEventArgs e)
        {
            
            IInvokeProvider invokeProvider = _peer.GetPattern(PatternInterface.Invoke) as IInvokeProvider;
            ((Button)((System.Windows.Automation.Peers.FrameworkElementAutomationPeer)(invokeProvider)).Owner).GotFocus -= DefaultEnterButtonTrigger_GotFocus;
            invokeProvider.Invoke();
        }

Reply

Great blog, exactly what I was looking for.
Thanks for sharing!

- Maskotki Pluszaki

Reply

Thanks. Great Post.
Triggers and Behaviors are amazing capabilities.

You should correct the attaching XAML. The trigger is called DefaultEnterButtonTrigger, but in the XAML you refer it as DefaultEnterButtonBehavior. Also the namespace is incorrect. It does compiled in the Word Smile

Reply

That Silverlight trigger is very useful.

- Gaz

Reply

Pedro Hon&#243;rio Silva
Portugal Pedro Honório Silva says:

Hi there!

Thanks for a fantastic post Dan.

I'm having an issue with this tho. I have a DataGrid with a data listing and I'm trying to allow the user to press enter on the selected item and it should do the same as pressing the edit button in that page (Show a ChildWindow with the data to be edited).

I'm using this trigger inside a datagrid in order to accomplish that behaviour but if I use it just like it is described in your blog, pressing enter on the datagrid will only make the selected item move forward one item and it doesn't show up the edititem window...

I'm quite new to Silverlight so I really don't have a clue why this is happening... Any help would be very appreciated! Thanks!

Reply

Add comment

  Country flag

biuquote
  • Comment
  • Preview
Loading