Consider pretty much standard Attached Property for some derived type:
public class DerivedKeyBinding : KeyBinding
{
public string Name; //shortened, make this propdp
}
public class KeyBindingExtenstions
{
public static DerivedKeyBinding GetCommand(DependencyObject obj) {
return (DerivedKeyBinding)obj.GetValue(CommandProperty);
}
public static void SetCommand(DependencyObject obj, DerivedKeyBinding value) {
obj.SetValue(CommandProperty, value);
}
public static readonly DependencyProperty CommandProperty =
DependencyProperty.RegisterAttached("Command", typeof(DerivedKeyBinding), typeof(KeyBindingExtenstions), new UIPropertyMetadata(null, CommandChanged));
private static void CommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
var commandValue = GetCommand(d);
}
}
which is later set in XAML:
<Grid>
<Grid.Style>
<Style>
<Setter Property="local:KeyBindingExtenstions.Command">
<Setter.Value>
<local:DerivedKeyBinding Name="{Binding Title, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"/>
</Setter.Value>
</Setter>
</Style>
</Grid.Style>
</Grid>
This will, however, crash on the var commandValue = GetCommand(d);
line due to local:DerivedKeyBinding
lost to KeyBinding
somewhere in process.
For some weird reason the property of DerivedKeyBinding
type is being set with value of type KeyBinding
(even though value is explicitly set to DerivedKeyBinding
in XAML).
System.InvalidCastException: 'Unable to cast object of type 'System.Windows.Input.KeyBinding' to type 'AttachedPropertyInStyle.DerivedKeyBinding'.'
Why is this happening and how can I fix the issue?
The issue seems to be connected to the Name
binding - if it is static value, the code executes flawlessly.
Override KeyBinding.CreateInstanceCore
. From Microsoft Docs:
Notes to Inheritors
Every Freezable derived class must implement this method. A typical implementation is to simply call the default constructor and return the result.
public class DerivedKeyBinding : KeyBinding
{
...
protected override Freezable CreateInstanceCore()
{
return new DerivedKeyBinding();
}
}
In the PropertyChangedCallback you may also write:
var commandValue = (DerivedKeyBinding)e.NewValue;