I have a custom button control that does not derive from Button. Is it possible for me to implement the equivalent of IsDefault so that the command associated with my control will be invoked. I was hoping that this was an attached property that I could add to any control but as far as I can tell it doesn't seem to be. Am I out of luck if my control does not derive from Button or is there at least a reasonable workaround?
UPDATE: I just took a peak with reflector at how this is being done underneath for Button and I must say it isn't the most self explanitory code I've seen. It appears that there are at least 3 dependency properties a few custom types just for the purpose of handling the concept of a Button being default. Since there doesn't seem to be an existing way to borrow the IsDefault functionality I suppose I'll have to narrow down what I'm trying to achieve so that I can at least get default focus and access key handling to work and just ignore the complexity invloved in the Button.IsDefault implementation.
UPDATE: Added the following code example showing my uncessful attempt at trying itowlson's suggestions.
MyButton.xaml
<UserControl x:Class="IsDefault.MyButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
Height="28"
Width="117">
<Grid>
<Button Click="Button_Click">
<Button.Template>
<ControlTemplate>
<Border BorderThickness="2"
CornerRadius="12"
Background="DarkSlateBlue">
<TextBlock Foreground="WhiteSmoke"
HorizontalAlignment="Center"
VerticalAlignment="Center">Some Text</TextBlock>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
</Grid>
</UserControl>
MyButton.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace IsDefault
{
/// <summary>
/// Interaction logic for MyButton.xaml
/// </summary>
public partial class MyButton : UserControl
{
// Provide CLR accessors for the event
public event RoutedEventHandler Click
{
add { AddHandler(ClickEvent, value); }
remove { RemoveHandler(ClickEvent, value); }
}
// Using a RoutedEvent
public static readonly RoutedEvent ClickEvent = EventManager.RegisterRoutedEvent(
"Click", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyButton));
public bool IsDefault
{
get { return (bool)GetValue(IsDefaultProperty); }
set { SetValue(IsDefaultProperty, value); }
}
public static readonly DependencyProperty IsDefaultProperty =
DependencyProperty.Register(
"IsDefault",
typeof(bool),
typeof(MyButton),
new PropertyMetadata(false, IsDefault_PropertyChangedCallback, null));
public MyButton()
{
InitializeComponent();
}
protected override void OnAccessKey(AccessKeyEventArgs e)
{
base.OnAccessKey(e);
if (e.Key == "\r")
{
if (e.IsMultiple)
{
// There are multiple controls that are currently handling the Enter key
MessageBox.Show("there are multiple controls handling the Enter key.");
}
else
{
RaiseEvent(new RoutedEventArgs(ClickEvent, this));
}
}
}
private static void IsDefault_PropertyChangedCallback(
DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var button = d as MyButton;
var isDefault = (bool)e.NewValue;
if (isDefault)
{
AccessKeyManager.Register("\r", button);
}
else
{
AccessKeyManager.Unregister("\r", button);
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(ClickEvent));
}
}
}
MainWindow.xaml
<Window x:Class="IsDefault.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
xmlns:my="clr-namespace:IsDefault">
<Grid>
<Button Content="Button"
Height="23"
HorizontalAlignment="Left"
Margin="224,24,0,0"
Name="button1"
VerticalAlignment="Top"
Width="75" />
<TextBox Height="23"
HorizontalAlignment="Left"
Margin="208,94,0,0"
Name="textBox1"
VerticalAlignment="Top"
Width="120" />
<my:MyButton Height="28"
HorizontalAlignment="Left"
Margin="232,154,0,0"
x:Name="myButton1"
VerticalAlignment="Top"
Width="117"
Click="myButton1_Click"
IsDefault="True"/>
</Grid>
</Window>
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace IsDefault
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void myButton1_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("My button was clicked, yay!");
}
}
}