defining-wpf-dependencyproperty

WPF DependencyProperty Patterns

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "defining-wpf-dependencyproperty" with this command: npx skills add christian289/dotnet-with-claudecode/christian289-dotnet-with-claudecode-defining-wpf-dependencyproperty

WPF DependencyProperty Patterns

Defining dependency properties for data binding, styling, animation, and property value inheritance.

Advanced Patterns: See ADVANCED.md for value inheritance, metadata override, and event integration.

  1. DependencyProperty Overview

Standard CLR Property: private string _name; public string Name { get => _name; set => _name = value; }

DependencyProperty: public static readonly DependencyProperty NameProperty = ... public string Name { get => (string)GetValue(NameProperty); set => SetValue(NameProperty, value); }

Benefits: ✅ Data Binding ✅ Styling & Templating ✅ Animation ✅ Property Value Inheritance ✅ Default Values ✅ Change Notifications ✅ Value Coercion ✅ Validation

  1. Basic DependencyProperty

2.1 Standard Registration

namespace MyApp.Controls;

using System.Windows; using System.Windows.Controls;

public class MyControl : Control { // 1. Register DependencyProperty public static readonly DependencyProperty TitleProperty = DependencyProperty.Register( name: nameof(Title), propertyType: typeof(string), ownerType: typeof(MyControl), typeMetadata: new PropertyMetadata(defaultValue: string.Empty));

// 2. CLR property wrapper
public string Title
{
    get => (string)GetValue(TitleProperty);
    set => SetValue(TitleProperty, value);
}

}

2.2 With FrameworkPropertyMetadata

public static readonly DependencyProperty ValueProperty = DependencyProperty.Register( name: nameof(Value), propertyType: typeof(double), ownerType: typeof(MyControl), typeMetadata: new FrameworkPropertyMetadata( defaultValue: 0.0, flags: FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, propertyChangedCallback: OnValueChanged, coerceValueCallback: CoerceValue), validateValueCallback: ValidateValue);

public double Value { get => (double)GetValue(ValueProperty); set => SetValue(ValueProperty, value); }

  1. FrameworkPropertyMetadataOptions

Flag Description

None No special behavior

AffectsMeasure Triggers Measure pass on change

AffectsArrange Triggers Arrange pass on change

AffectsRender Triggers Render on change

Inherits Value inherits to child elements

BindsTwoWayByDefault Default binding mode is TwoWay

Common Combinations

// Read-only display property (AffectsRender) new FrameworkPropertyMetadata( defaultValue: null, flags: FrameworkPropertyMetadataOptions.AffectsRender);

// Layout-affecting property (AffectsMeasure) new FrameworkPropertyMetadata( defaultValue: 100.0, flags: FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange);

// Two-way bindable property new FrameworkPropertyMetadata( defaultValue: false, flags: FrameworkPropertyMetadataOptions.BindsTwoWayByDefault);

  1. Callbacks

4.1 PropertyChangedCallback

public static readonly DependencyProperty IsActiveProperty = DependencyProperty.Register( nameof(IsActive), typeof(bool), typeof(MyControl), new PropertyMetadata(false, OnIsActiveChanged));

private static void OnIsActiveChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var control = (MyControl)d; var oldValue = (bool)e.OldValue; var newValue = (bool)e.NewValue;

// Handle property change
control.UpdateVisualState(newValue);

}

4.2 CoerceValueCallback

public static readonly DependencyProperty ProgressProperty = DependencyProperty.Register( nameof(Progress), typeof(double), typeof(ProgressControl), new FrameworkPropertyMetadata( 0.0, propertyChangedCallback: null, coerceValueCallback: CoerceProgress));

private static object CoerceProgress(DependencyObject d, object baseValue) { var value = (double)baseValue;

// Clamp value to valid range
if (value < 0.0) return 0.0;
if (value > 100.0) return 100.0;

return value;

}

4.3 ValidateValueCallback

public static readonly DependencyProperty CountProperty = DependencyProperty.Register( nameof(Count), typeof(int), typeof(MyControl), new PropertyMetadata(0), ValidateCount); // Note: Not part of PropertyMetadata

private static bool ValidateCount(object value) { var count = (int)value;

// Return false to reject the value (throws exception)
return count >= 0;

}

4.4 Callback Execution Order

  1. ValidateValueCallback - Can reject value (throw exception)

  2. CoerceValueCallback - Can modify value

  3. PropertyChangedCallback - Handle the change

  4. Read-Only DependencyProperty

namespace MyApp.Controls;

using System.Windows;

public class StatusControl : Control { // 1. Register read-only property key (private) private static readonly DependencyPropertyKey IsConnectedPropertyKey = DependencyProperty.RegisterReadOnly( nameof(IsConnected), typeof(bool), typeof(StatusControl), new FrameworkPropertyMetadata(false));

// 2. Expose public DependencyProperty
public static readonly DependencyProperty IsConnectedProperty =
    IsConnectedPropertyKey.DependencyProperty;

// 3. Read-only CLR property
public bool IsConnected => (bool)GetValue(IsConnectedProperty);

// 4. Internal setter using key
protected void SetIsConnected(bool value)
{
    SetValue(IsConnectedPropertyKey, value);
}

}

  1. Attached Property

6.1 Defining Attached Property

namespace MyApp.Attached;

using System.Windows;

public static class GridHelper { // Register attached property public static readonly DependencyProperty ColumnSpacingProperty = DependencyProperty.RegisterAttached( name: "ColumnSpacing", propertyType: typeof(double), ownerType: typeof(GridHelper), defaultMetadata: new FrameworkPropertyMetadata( 0.0, FrameworkPropertyMetadataOptions.AffectsMeasure, OnColumnSpacingChanged));

// Getter
public static double GetColumnSpacing(DependencyObject obj)
{
    return (double)obj.GetValue(ColumnSpacingProperty);
}

// Setter
public static void SetColumnSpacing(DependencyObject obj, double value)
{
    obj.SetValue(ColumnSpacingProperty, value);
}

private static void OnColumnSpacingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    if (d is Grid grid)
    {
        UpdateGridSpacing(grid, (double)e.NewValue);
    }
}

private static void UpdateGridSpacing(Grid grid, double spacing)
{
    // Implementation
}

}

6.2 Using Attached Property in XAML

<Grid local:GridHelper.ColumnSpacing="10"> <Grid.ColumnDefinitions> <ColumnDefinition Width=""/> <ColumnDefinition Width=""/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <!-- Children --> </Grid>

  1. References
  • Dependency Properties Overview - Microsoft Docs

  • Custom Dependency Properties - Microsoft Docs

  • Attached Properties Overview - Microsoft Docs

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

converting-html-css-to-wpf-xaml

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

managing-styles-resourcedictionary

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

using-xaml-property-element-syntax

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

designing-avalonia-customcontrol-architecture

No summary provided by upstream source.

Repository SourceNeeds Review