defining-wpf-dependencyproperty
Defines WPF DependencyProperty with Register, PropertyMetadata, callbacks, and validation. Use when creating custom controls, attached properties, or properties that support data binding and styling.
What this skill does
# WPF DependencyProperty Patterns
Defining dependency properties for data binding, styling, animation, and property value inheritance.
**Advanced Patterns:** See [ADVANCED.md](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
```
---
## 2. Basic DependencyProperty
### 2.1 Standard Registration
```csharp
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
```csharp
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);
}
```
---
## 3. 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
```csharp
// 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);
```
---
## 4. Callbacks
### 4.1 PropertyChangedCallback
```csharp
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
```csharp
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
```csharp
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
```
---
## 5. Read-Only DependencyProperty
```csharp
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);
}
}
```
---
## 6. Attached Property
### 6.1 Defining Attached Property
```csharp
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
```xml
<Grid local:GridHelper.ColumnSpacing="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- Children -->
</Grid>
```
---
## 7. References
- [Dependency Properties Overview - Microsoft Docs](https://learn.microsoft.com/en-us/dotnet/desktop/wpf/properties/dependency-properties-overview)
- [Custom Dependency Properties - Microsoft Docs](https://learn.microsoft.com/en-us/dotnet/desktop/wpf/properties/custom-dependency-properties)
- [Attached Properties Overview - Microsoft Docs](https://learn.microsoft.com/en-us/dotnet/desktop/wpf/properties/attached-properties-overview)
Related in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.