WPF 元素多數功能透過屬性暴露,相依性屬性(DP)系統提供標準 CLR 屬性無法比擬的能力:
FontFamily、Cursor)。public class MyCustomControl : ContentControl {
public static readonly DependencyProperty FooProperty =
DependencyProperty.Register("Foo", typeof(Brush),
typeof(MyCustomControl), new PropertyMetadata(Brushes.Green));
public Brush Foo {
get { return (Brush)GetValue(FooProperty); }
set { SetValue(FooProperty, value); }
}
}
public static readonly DependencyProperty XxxProperty。PropertyMetadata 指定預設值、變更回呼等。GetValue/SetValue,方便 XAML 與程式碼使用。用 RegisterAttached 註冊,提供靜態 GetXxx/SetXxx 存取器:
public static readonly DependencyProperty IsBarProperty =
DependencyProperty.RegisterAttached("IsBar", typeof(bool),
typeof(ControlWithAttachedProp), new PropertyMetadata(false));
public static bool GetIsBar(DependencyObject target) => (bool)target.GetValue(IsBarProperty);
public static void SetIsBar(DependencyObject target, bool value) => target.SetValue(IsBarProperty, value);
XAML 使用:<Button local:ControlWithAttachedProp.IsBar="true" />
在 PropertyMetadata 傳入 PropertyInvalidatedCallback:
static ControlWithAttachedProp() {
var callback = new PropertyInvalidatedCallback(OnIsBarChanged);
var meta = new PropertyMetadata(false, callback);
IsBarProperty = DependencyProperty.RegisterAttached("IsBar", typeof(bool),
typeof(ControlWithAttachedProp), meta);
}
static void OnIsBarChanged(DependencyObject target) {
Debug.WriteLine("IsBar changed: " + GetIsBar(target));
}
在靜態建構式用 EventManager.RegisterRoutedEvent 註冊,提供 CLR 事件包裝器轉呼 AddHandler/RemoveHandler:
public static readonly RoutedEvent BarEvent =
EventManager.RegisterRoutedEvent("Bar", RoutingStrategy.Bubble,
typeof(RoutedEventHandler), typeof(MyCustomControl));
public event RoutedEventHandler Bar {
add { AddHandler(BarEvent, value); }
remove { RemoveHandler(BarEvent, value); }
}
protected virtual void OnBar() {
var args = new RoutedEventArgs(PreviewBarEvent);
RaiseEvent(args);
if (!args.Handled) {
args = new RoutedEventArgs(BarEvent);
RaiseEvent(args);
}
}
PreviewXxx (Tunnel) 與 Xxx (Bubble)。RaiseEvent 同步呼叫所有處理器。路由事件天生支援附屬用法,無需特殊註冊:
myButton.AddHandler(MyCustomControl.BarEvent, handler);
myButton.RaiseEvent(new RoutedEventArgs(MyCustomControl.BarEvent));
public static readonly RoutedCommand FooCommand =
new RoutedCommand("Foo", typeof(MyControl),
new InputGestureCollection { new KeyGesture(Key.F, ModifierKeys.Control | ModifierKeys.Shift) });
XAML 綁定:<Button Command="local:MyControl.FooCommand">Click me</Button>
在靜態建構式用 CommandManager.RegisterClassCommandBinding 註冊,處理器必須為 static:
static MyCustomControl() {
var binding = new CommandBinding(ApplicationCommands.Copy, HandleCopyCommand);
CommandManager.RegisterClassCommandBinding(typeof(MyCustomControl), binding);
}
private static void HandleCopyCommand(object target, ExecutedRoutedEventArgs e) {
var ctrl = (MyCustomControl)target;
// 實作複製邏輯
}