For a few months I have been successfully using David Justices Default Button example in my SL 3 app. This approach is based on an attached property.
After upgrading to SL4, the approach no longer works, and I get a XAML exception:
Unknown parser error: Scanner 2148474880
Has anyone succesfully used this (or any other) default button attached behaviours in SL4?
Is there any other way to achieve default button behaviour in SL4 with the new classes that are available?
Thanks, Mark
The final solution for us also had to get around the issue where the backing property was not being updated prior to the button click occuring (as in all MVVM patterns)....
Note: peer.SetFocus();
Edit: Added XAML example.
public static 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) => {
var peer = new ButtonAutomationPeer(button);
if (arg.Key == Key.Enter) {
peer.SetFocus();
uiElement.Dispatcher.BeginInvoke((Action)delegate {
var invokeProv =
peer.GetPattern(PatternInterface.Invoke) as IInvokeProvider;
if (invokeProv != null)
invokeProv.Invoke();
});
}
};
}
}
public static Button GetDefaultButton(UIElement obj) {
return (Button)obj.GetValue(DefaultButtonProperty);
}
public static void SetDefaultButton(DependencyObject obj, Button button) {
obj.SetValue(DefaultButtonProperty, button);
}
}
How to apply in XAML:
<StackPanel>
<TextBox DinnerConfig:DefaultButtonService.DefaultButton="{Binding ElementName=MyButton}"
Text="Press Enter" />
<Button x:Name="MyButton"
Content="Click me" />
</StackPanel>
I was really hoping that there would be a out of the box solution for such a common use-case in Silverlight 4, but unfortunately I don't think there is.
There is another Default Button implementation by Patrick Cauldwell. He's also using Attached Properties.
I've tested this in a SL 4 application and it seems to do the job.
You can find the code here: http://www.cauldwell.net/patrick/blog/DefaultButtonSemanticsInSilverlightRevisited.aspx
Edit: I've tweaked David Justice's code to get it working for Silverlight 4. I've just changed the GetDefaultButton and SetDefaultButton to take and return a DefaultButtonService. Usage is the same as noted on his website. This should work for you:
Edit2: Added XAML example for clarity.
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 peer = new ButtonAutomationPeer(button);
var invokeProv =
peer.GetPattern(PatternInterface.Invoke) as IInvokeProvider;
if (invokeProv != null)
invokeProv.Invoke();
}
};
}
}
public static DefaultButtonService GetDefaultButton(UIElement obj)
{
return (DefaultButtonService)obj.GetValue(DefaultButtonProperty);
}
public static void SetDefaultButton(DependencyObject obj, DefaultButtonService button)
{
obj.SetValue(DefaultButtonProperty, button);
}
}
How to apply in XAML:
<StackPanel>
<TextBox DinnerConfig:DefaultButtonService.DefaultButton="{Binding ElementName=MyButton}"
Text="Press Enter" />
<Button x:Name="MyButton"
Content="Click me" />
</StackPanel>
I extended David's approach by allowing a custom key (defaulted to Enter) to be set in an additional property:
public static DependencyProperty ButtonKeyProperty = DependencyProperty.RegisterAttached(
"ButtonKey",
typeof(Key),
typeof(Defaults),
new PropertyMetadata(Key.Enter, ButtonChanged));
public static void SetButtonKey(DependencyObject dependencyObj, Key key)
{
dependencyObj.SetValue(ButtonKeyProperty, key);
}
public static Key GetButtonKey(DependencyObject dependencyObj)
{
return (Key)dependencyObj.GetValue(ButtonKeyProperty);
}
I modified the original property to then leverage this property:
Key key = GetButtonKey(dependencyObj);
if (button.IsEnabled && keyEvent.Key == key)
...
So now, for example, I can use Escape as the key if I want (note I changed the named of the classes and properties):
... UI:Defaults.Button="{Binding ElementName=myButton}" UI:Defaults.ButtonKey="Escape" ...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With