posts - 28 , comments - 23 , trackbacks - 0

My Links

News

Twitter












Tag Cloud

Archives

Building on someone else's DefaultButton Silverlight work...

This week I was handed a "simple" requirement - have a search screen execute its search when the user pressed the Enter key instead of having to move hands from keyboard to mouse and click Search.  That is a reasonable request that has been met for years both in Windows and Web apps.  I did a quick scan for code to pilfer and found Patrick Cauldwell's Blog posting "A 'Default Button' In Silverlight".  This posting was a great start and I'm glad that the basic work had been done for me, but I ran into one issue - when using bound textboxes (I'm a die-hard MVVM enthusiast when it comes to Silverlight development), the search was being executed before the textbox I was in when the Enter key was pressed updated its bindings.  With a little bit of reflection work, I think I have found a good generic solution that builds upon Patrick's to make it more binding-friendly.  Also, I wanted to set the DefaultButton at a higher level than on each TextBox (or other control for that matter), so the use of mine is intended to be set somewhere such as the LayoutRoot or other high level control and will apply to all controls beneath it in the control tree.  I haven't tested this on controls that treat the Enter key special themselves in the mix.

The real change from Patrick's solution here is that in the KeyUp event, I grab the source of the KeyUp event (in my case the textbox containing search criteria) and loop through the static fields on the element's type looking for DependencyProperty instances.  When I find a DependencyProperty, I grab the value and query for bindings.  Each time I find a binding, UpdateSource is called to make sure anything bound to any property of the field has the opportunity to update before the action represented by the DefaultButton is executed.

Here's the code:

public class DefaultButtonService
{
public static DependencyProperty DefaultButtonProperty = DependencyProperty.RegisterAttached("DefaultButton",
typeof (Button),
typeof (DefaultButtonService),
new PropertyMetadata
(null,
DefaultButtonChanged));

private static void DefaultButtonChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var uiElement = d as UIElement;
var button = e.NewValue as Button;
if (uiElement != null && button != null)
{
uiElement.KeyUp += (sender, arg) =>
{
if (arg.Key == Key.Enter)
{
var element = arg.OriginalSource as FrameworkElement;
if (element != null)
{
UpdateBindings(element);
}

if (button.IsEnabled)
{
button.Focus();
var peer = new ButtonAutomationPeer(button);
var invokeProv =
peer.GetPattern(PatternInterface.Invoke) as IInvokeProvider;
if (invokeProv != null) invokeProv.Invoke();
arg.Handled = true;
}
}
};
}
}

public static DefaultButtonService GetDefaultButton(UIElement obj)
{
return (DefaultButtonService) obj.GetValue(DefaultButtonProperty);
}

public static void SetDefaultButton(DependencyObject obj, DefaultButtonService button)
{
obj.SetValue(DefaultButtonProperty, button);
}

public static void UpdateBindings(FrameworkElement element)
{
element.GetType().GetFields(BindingFlags.Public | BindingFlags.Static).ForEach(field =>
{
if (field.FieldType.IsAssignableFrom(typeof(DependencyProperty)))
{
try
{
var dp = field.GetValue(null) as DependencyProperty;
if (dp != null)
{
var binding = element.GetBindingExpression(dp);
if (binding != null)
{
binding.UpdateSource();
}
}
}
// ReSharper disable EmptyGeneralCatchClause
catch (Exception)
// ReSharper restore EmptyGeneralCatchClause
{
// swallow exceptions
}
}
});
}
}

Print | posted on Friday, February 18, 2011 5:53 AM |

Feedback

Gravatar

# re: Building on someone else's DefaultButton Silverlight work...

Hi Kyle.

I'm getting an error here:

element.GetType().GetFields(BindingFlags.Public | BindingFlags.Static).ForEach(...);

saying that no overloaded method for ForEach accepts 1 argument.

I use Silverlight 4.

Do you have any idea how I can fix it?

I'm sure it's a stupid question, but I'm absolutely new to Silverlight... ;-)

TIA,
Johnny J.
7/21/2011 5:48 AM | Johnny Jörgensen
Gravatar

# re: Building on someone else's DefaultButton Silverlight work...

Hi Johnny, it's probably an issue with the original post being made while I had a reference to a library providing a ForEach extenstion method for Array (which, by the way, is a lead-in to what I consider a down side to extension messages so maybe there is a post in this). It can easily be remedied by changing the following line:

element.GetType().GetFields(BindingFlags.Public | BindingFlags.Static).ForEach(field =>

to a standard foreach:

foreach(var field in element.GetType().GetFields(BindingFlags.Public | BindingFlags.Static ))
7/21/2011 6:37 AM | Kyle
Post A Comment
Title:
Name:
Email:
Comment:
Verification:
 

Powered by: