Merge pull request #1207 from dotnet/main

Publish
This commit is contained in:
Andy (Steve) De George
2021-11-05 09:13:47 -07:00
committed by GitHub
36 changed files with 1246 additions and 14 deletions
+24
View File
@@ -520,6 +520,30 @@
{
"source_path": "dotnet-desktop-guide/framework/wpf/properties/collection-type-dependency-properties.md",
"redirect_url": "/dotnet/desktop/wpf/advanced/collection-type-dependency-properties?view=netframeworkdesktop-4.8"
},
{
"source_path": "dotnet-desktop-guide/net/wpf/advanced/custom-dependency-properties.md",
"redirect_url": "/dotnet/desktop/wpf/properties/custom-dependency-properties?view=netdesktop-5.0"
},
{
"source_path": "dotnet-desktop-guide/framework/wpf/properties/custom-dependency-properties.md",
"redirect_url": "/dotnet/desktop/wpf/advanced/custom-dependency-properties?view=netframeworkdesktop-4.8"
},
{
"source_path": "dotnet-desktop-guide/net/wpf/advanced/dependency-property-metadata.md",
"redirect_url": "/dotnet/desktop/wpf/properties/dependency-property-metadata?view=netdesktop-5.0"
},
{
"source_path": "dotnet-desktop-guide/framework/wpf/properties/dependency-property-metadata.md",
"redirect_url": "/dotnet/desktop/wpf/advanced/dependency-property-metadata?view=netframeworkdesktop-4.8"
},
{
"source_path": "dotnet-desktop-guide/net/wpf/advanced/how-to-override-metadata-for-a-dependency-property.md",
"redirect_url": "/dotnet/desktop/wpf/properties/how-to-override-metadata-for-a-dependency-property?view=netdesktop-5.0"
},
{
"source_path": "dotnet-desktop-guide/framework/wpf/properties/how-to-override-metadata-for-a-dependency-property.md",
"redirect_url": "/dotnet/desktop/wpf/advanced/how-to-override-metadata-for-a-dependency-property?view=netframeworkdesktop-4.8"
}
]
}
@@ -0,0 +1,170 @@
---
title: "Custom dependency properties"
description: Learn how to implement a dependency property in Windows Presentation Foundation (WPF), and how to improve its performance, usability, or versatility.
ms.date: "10/20/2021"
ms.topic: overview
dev_langs:
- "csharp"
- "vb"
helpviewer_keywords:
- "implementing [WPF], wrappers"
- "registering properties [WPF]"
- "properties [WPF], metadata"
- "metadata [WPF], for properties"
- "custom dependency properties [WPF]"
- "properties [WPF], registering"
- "wrappers [WPF], implementing"
- "dependency properties [WPF], custom"
---
<!-- The acrolinx score was 94 on 10/20/2021-->
# Custom dependency properties (WPF .NET)
Windows Presentation Foundation (WPF) application developers and component authors can create custom dependency properties to extend the functionality of their properties. Unlike a common language runtime (CLR) [property](/dotnet/standard/base-types/common-type-system#properties), a dependency property adds support for styling, data binding, inheritance, animations, and default values. <xref:System.Windows.Controls.Control.Background%2A>, <xref:System.Windows.FrameworkElement.Width%2A>, and <xref:System.Windows.Controls.TextBox.Text%2A> are examples of existing dependency properties in WPF classes. This article describes how to implement custom dependency properties, and presents options for improving performance, usability, and versatility.
## Prerequisites
The article assumes a basic knowledge of dependency properties, and that you've read [Dependency properties overview](dependency-properties-overview.md). To follow the examples in this article, it helps if you're familiar with Extensible Application Markup Language (XAML) and know how to write WPF applications.
## Dependency property identifier
Dependency properties are properties that are registered with the WPF property system through <xref:System.Windows.DependencyProperty.Register%2A> or <xref:System.Windows.DependencyProperty.RegisterReadOnly%2A> calls. The `Register` method returns a <xref:System.Windows.DependencyProperty> instance that holds the registered name and characteristics of a dependency property. You'll assign the `DependencyProperty` instance to a static readonly field, known as a *dependency property identifier*, that by convention is named `<property name>Property`. For example, the identifier field for the <xref:System.Windows.Controls.Control.Background%2A> property is always <xref:System.Windows.Controls.Control.BackgroundProperty>.
The dependency property identifier is used as a backing field for getting or setting property values, rather than the standard pattern of backing a property with a private field. Not only does the property system uses the identifier, XAML processors may use it, and your code (and possibly external code) can access dependency properties through their identifiers.
Dependency properties can only be applied to classes that are derived from <xref:System.Windows.DependencyObject> types. Most WPF classes support dependency properties, because `DependencyObject` is close to the root of the WPF class hierarchy. For more information about dependency properties, and the terminology and conventions used to describe them, see [Dependency properties overview](dependency-properties-overview.md).
## Dependency property wrappers
WPF dependency properties that aren't attached properties are exposed by a CLR wrapper that implements `get` and `set` accessors. By using a property wrapper, consumers of dependency properties can get or set dependency property values, just as they would any other CLR property. The `get` and `set` accessors interact with the underlying property system through <xref:System.Windows.DependencyObject.GetValue%2A?displayProperty=nameWithType> and <xref:System.Windows.DependencyObject.SetValue%2A?displayProperty=nameWithType> calls, passing in the dependency property identifier as a parameter. Consumers of dependency properties typically don't call `GetValue` or `SetValue` directly, but if you're implementing a custom dependency property you'll use those methods in the wrapper.
## When to implement a dependency property
When you implement a property on a class that derives from <xref:System.Windows.DependencyObject>, you make it a dependency property by backing your property with a <xref:System.Windows.DependencyProperty> identifier. Whether it's beneficial to create a dependency property depends on your scenario. Although backing your property with a private field is adequate for some scenarios, consider implementing a dependency property if you want your property to support one or more of the following WPF capabilities:
- Properties that are settable within a style. For more information, see [Styles and templates](../controls/styles-templates-overview.md).
- Properties that support data binding. For more information about data binding dependency properties, see [Bind the properties of two controls](/dotnet/desktop/wpf/data/how-to-bind-the-properties-of-two-controls?view=netframeworkdesktop-4.8&preserve-view=true).
- Properties that are settable through dynamic resource references. For more information, see [XAML resources](/dotnet/desktop-wpf/fundamentals/xaml-resources-define).
- Properties that automatically inherit their value from a parent element in the element tree. For this, you'll need to register using <xref:System.Windows.DependencyProperty.RegisterAttached%2A>, even if you also create a property wrapper for CLR access. For more information, see [Property value inheritance](/dotnet/desktop/wpf/advanced/property-value-inheritance?view=netframeworkdesktop-4.8&preserve-view=true).
- Properties that are animatable. For more information, see [Animation overview](/dotnet/desktop/wpf/graphics-multimedia/animation-overview?view=netframeworkdesktop-4.8&preserve-view=true).
- Notification by the WPF property system when a property value changes. Changes might be due to actions by the property system, environment, user, or styles. Your property can specify a callback method in property metadata that will get invoked each time the property system determines that your property value changed. A related concept is property value coercion. For more information, see [Dependency property callbacks and validation](/dotnet/desktop/wpf/advanced/dependency-property-callbacks-and-validation?view=netframeworkdesktop-4.8&preserve-view=true).
- Access to dependency property metadata, which is read by WPF processes. For example, you can use property metadata to:
- Specify whether a changed dependency property value should make the layout system recompose visuals for an element.
- Set the default value of a dependency property, by overriding metadata on derived classes.
- Visual Studio WPF designer support, such as editing the properties of a custom control in the **Properties** window. For more information, see [Control authoring overview](/dotnet/desktop/wpf/controls/control-authoring-overview?view=netframeworkdesktop-4.8&preserve-view=true).
For some scenarios, overriding the metadata of an existing dependency property is a better option than implementing a new dependency property. Whether a metadata override is practical depends on your scenario, and how closely that scenario resembles the implementation of existing WPF dependency properties and classes. For more information about overriding metadata on existing dependency properties, see [Dependency property metadata](/dotnet/desktop/wpf/advanced/dependency-property-metadata?view=netframeworkdesktop-4.8&preserve-view=true).
## Checklist for creating a dependency property
Follow these steps to create a dependency property. Some of the steps can be combined and implemented in a single line of code.
1. (Optional) Create dependency property metadata.
1. Register the dependency property with the property system, specifying a property name, an owner type, the property value type, and optionally, property metadata.
1. Define a <xref:System.Windows.DependencyProperty> identifier as a `public static readonly` field on the owner type. The identifier field name is the property name with the suffix `Property` appended.
1. Define a CLR wrapper property with the same name as the dependency property name. In the CLR wrapper, implement `get` and `set` accessors that connect with the dependency property that backs the wrapper.
### Registering the property
In order for your property to be a dependency property, you must register it with the property system. To register your property, call the <xref:System.Windows.DependencyProperty.Register%2A> method from inside the body of your class, but outside of any member definitions. The `Register` method returns a unique dependency property identifier that you'll use when calling the property system API. The reason that the `Register` call is made outside of member definitions is because you assign the return value to a `public static readonly` field of type <xref:System.Windows.DependencyProperty>. This field, which you'll create in your class, is the identifier for your dependency property. In the following example, the first argument of `Register` names the dependency property `AquariumGraphic`.
:::code language="csharp" source="./snippets/custom-dependency-properties/csharp/MainWindow.xaml.cs" id="RegisterDependencyProperty":::
:::code language="vb" source="./snippets/custom-dependency-properties/vb/MainWindow.xaml.vb" id="RegisterDependencyProperty":::
> [!NOTE]
> Defining the dependency property in the class body is the typical implementation, but it's also possible to define a dependency property in the class static constructor. This approach might make sense if you need more than one line of code to initialize the dependency property.
### Dependency property naming
The established naming convention for dependency properties is mandatory for normal behavior of the property system. The name of the identifier field that you create must be the registered name of the property with the suffix `Property`.
A dependency property name must be unique within the registering class. Dependency properties that are inherited through a base type have already been registered, and cannot be registered by a derived type. However, you can use a dependency property that was registered by a different type, even a type your class doesn't inherit from, by adding your class as an owner of the dependency property. For more information on adding a class as owner, see [Dependency property metadata](/dotnet/desktop/wpf/advanced/dependency-property-metadata?view=netframeworkdesktop-4.8&preserve-view=true#adding-a-class-as-an-owner-of-an-existing-dependency-property).
### Implementing a property wrapper
By convention, the name of the wrapper property must be the same as the first parameter of the <xref:System.Windows.DependencyProperty.Register%2A> call, which is the dependency property name. Your wrapper implementation will call <xref:System.Windows.DependencyObject.GetValue%2A> in the `get` accessor, and <xref:System.Windows.DependencyObject.SetValue%2A> in the `set` accessor (for read-write properties). The following example shows a wrapper&mdash;following the registration call and identifier field declaration. All public dependency properties on WPF classes use a similar wrapper model.
:::code language="csharp" source="./snippets/custom-dependency-properties/csharp/MainWindow.xaml.cs" id="RegisterDependencyPropertyWithWrapper":::
:::code language="vb" source="./snippets/custom-dependency-properties/vb/MainWindow.xaml.vb" id="RegisterDependencyPropertyWithWrapper":::
Except in rare cases, your wrapper implementation should only contain <xref:System.Windows.DependencyObject.GetValue%2A> and <xref:System.Windows.DependencyObject.SetValue%2A> code. For the reasons behind this, see [Implications for custom dependency properties](/dotnet/desktop/wpf/advanced/xaml-loading-and-dependency-properties?view=netframeworkdesktop-4.8&preserve-view=true#implications-for-custom-dependency-properties).
If your property doesn't follow established naming conventions, you might run into these issues:
- Some aspects of styles and templates won't work.
- Most tools and designers rely on the naming conventions to properly serialize XAML and provide designer environment assistance at a per-property level.
- The current implementation of the WPF XAML loader bypasses the wrappers entirely, and relies on the naming convention to process attribute values. For more information, see [XAML loading and dependency properties](/dotnet/desktop/wpf/advanced/xaml-loading-and-dependency-properties?view=netframeworkdesktop-4.8&preserve-view=true).
### Dependency property metadata
When you register a dependency property, the property system creates a metadata object to store property characteristics. Overloads of the <xref:System.Windows.DependencyProperty.Register%2A> method let you specify property metadata during registration, for example <xref:System.Windows.DependencyProperty.Register%28System.String%2CSystem.Type%2CSystem.Type%2CSystem.Windows.PropertyMetadata%29>. A common use of property metadata is to apply a custom default value for new instances that use a dependency property. If you don't provide property metadata, the property system will assign default values to many of the dependency property characteristics.
If you're creating a dependency property on a class derived from <xref:System.Windows.FrameworkElement>, you can use the more specialized metadata class <xref:System.Windows.FrameworkPropertyMetadata> rather than its base class <xref:System.Windows.PropertyMetadata>. Several <xref:System.Windows.FrameworkPropertyMetadata> constructor signatures let you specify different combinations of metadata characteristics. If you just want to specify a default value, then use <xref:System.Windows.FrameworkPropertyMetadata.%23ctor(System.Object)> and pass the default value to the `Object` parameter. Ensure that the value type matches the `propertyType` specified in the `Register` call.
Some <xref:System.Windows.FrameworkPropertyMetadata> overloads let you specify [metadata option flags](<xref:System.Windows.FrameworkPropertyMetadataOptions>) for your property. The property system converts these flags into discrete properties and the flag values are used by WPF processes, such as the layout engine.
#### Setting metadata flags
Consider the following when setting metadata flags:
- If your property value (or changes to it) affects how the layout system renders a UI element, then set one or more of the following flags:
- <xref:System.Windows.FrameworkPropertyMetadataOptions.AffectsMeasure>, which indicates that a change in property value requires a change in UI rendering, specifically the space occupied by an object within its parent. For example, set this metadata flag for a `Width` property.
- <xref:System.Windows.FrameworkPropertyMetadataOptions.AffectsArrange>, which indicates that a change in property value requires a change in UI rendering, specifically the position of an object within its parent. Typically, the object doesn't also change size. For example, set this metadata flag for an `Alignment` property.
- <xref:System.Windows.FrameworkPropertyMetadataOptions.AffectsRender>, which indicates that a change has occurred that doesn't affect layout and measure, but still requires another render. For example, set this flag for a `Background` property, or any other property that affects the color of an element.
You can use also these flags as inputs to your override implementations of the property system (or layout) callbacks. For example, you might use an <xref:System.Windows.DependencyObject.OnPropertyChanged%2A> callback to call <xref:System.Windows.UIElement.InvalidateArrange%2A> when a property of the instance reports a value change and has <xref:System.Windows.FrameworkPropertyMetadata.AffectsArrange%2A> set in metadata.
- Some properties affect the rendering characteristics of their parent element in other ways. For example, changes to the <xref:System.Windows.Documents.Paragraph.MinOrphanLines%2A> property can change the overall rendering of a flow document. Use <xref:System.Windows.FrameworkPropertyMetadataOptions.AffectsParentArrange> or <xref:System.Windows.FrameworkPropertyMetadataOptions.AffectsParentMeasure> to signal parent actions in your own properties.
- By default, dependency properties support data binding. However, you can use <xref:System.Windows.FrameworkPropertyMetadata.IsDataBindingAllowed> to disable data binding when there's no realistic scenario for it, or where data binding performance is problematic, such as on large objects.
- Although the default data binding [mode](<xref:System.Windows.Data.Binding.Mode%2A>) for dependency properties is <xref:System.Windows.Data.BindingMode.OneWay>, you can change the binding mode of a specific binding to <xref:System.Windows.Data.BindingMode.TwoWay>. For more information, see [Binding direction](/dotnet/desktop/wpf/data/binding-declarations-overview#binding-direction). As a dependency property author, you can even choose to make two-way binding the default mode. An example of an existing dependency property that uses two-way data binding is <xref:System.Windows.Controls.MenuItem.IsSubmenuOpen%2A?displayProperty=nameWithType>, which has a state that's based on other properties and method calls. The scenario for `IsSubmenuOpen` is that its setting logic, and the compositing of <xref:System.Windows.Controls.MenuItem>, interact with the default theme style. <xref:System.Windows.Controls.TextBox.Text%2A?displayProperty=nameWithType> is another WPF dependency property that uses two-way binding by default.
- You can enable property inheritance for your dependency property by setting the <xref:System.Windows.FrameworkPropertyMetadataOptions.Inherits> flag. Property inheritance is useful for scenarios in which parent and child elements have a property in common and it makes sense for the child element to inherit the parent value for the common property. An example of an inheritable property is <xref:System.Windows.FrameworkElement.DataContext%2A>, which supports binding operations that use the [master-detail scenario](/dotnet/desktop/wpf/data/how-to-use-the-master-detail-pattern-with-hierarchical-data?view=netframeworkdesktop-4.8&preserve-view=true) for data presentation. Property value inheritance lets you specify a data context at the page or application root, which saves having to specify it for child element bindings. Although an inherited property value overrides the default value, property values can be set locally on any child element. Use property value inheritance sparingly because it has a performance cost. For more information, see [Property value inheritance](/dotnet/desktop/wpf/advanced/property-value-inheritance?view=netframeworkdesktop-4.8&preserve-view=true).
- Set the <xref:System.Windows.FrameworkPropertyMetadataOptions.Journal> flag to indicate that your dependency property should be detected or used by navigation journaling services. For example, the <xref:System.Windows.Controls.Primitives.Selector.SelectedIndex%2A> property sets the `Journal` flag to recommend that applications keep a journaling history of items selected.
## Read-only dependency properties
You can define a dependency property that's read-only. A typical scenario is a dependency property that stores internal state. For example, <xref:System.Windows.UIElement.IsMouseOver> is read-only because its state should only be determined by mouse input. For more information, see [Read-only dependency properties](/dotnet/desktop/wpf/advanced/read-only-dependency-properties?view=netframeworkdesktop-4.8&preserve-view=true).
## Collection-type dependency properties
Collection-type dependency properties have extra implementation issues to consider, such as setting a default value for reference types and data binding support for collection elements. For more information, see [Collection-type dependency properties](/dotnet/desktop/wpf/advanced/collection-type-dependency-properties?view=netframeworkdesktop-4.8&preserve-view=true).
## Dependency property security
Typically, you'll declare dependency properties as public properties, and <xref:System.Windows.DependencyProperty> identifier fields as `public static readonly` fields. If you specify a more restrictive access level, such as `protected`, a dependency property can still be accessed through its identifier in combination with property system APIs. Even a protected identifier field is potentially accessible through WPF metadata reporting or value determination APIs, like <xref:System.Windows.LocalValueEnumerator>. For more information, see [Dependency property security](/dotnet/desktop/wpf/advanced/dependency-property-security?view=netframeworkdesktop-4.8&preserve-view=true).
For read-only dependency properties, the value returned from <xref:System.Windows.DependencyProperty.RegisterReadOnly%2A> is <xref:System.Windows.DependencyPropertyKey>, and typically you won't make `DependencyPropertyKey` a `public` member of your class. Because the WPF property system doesn't propagate the `DependencyPropertyKey` outside of your code, a read-only dependency property has better `set` security than a read-write dependency property.
## Dependency properties and class constructors
There's a general principle in managed code programming, often enforced by code analysis tools, that class constructors shouldn't call virtual methods. This is because base constructors can be called during initialization of a derived class constructor, and a virtual method called by a base constructor might run before complete initialization of the derived class. When you derive from a class that already derives from <xref:System.Windows.DependencyObject>, the property system itself calls and exposes virtual methods internally. These virtual methods are part of the WPF property system services. Overriding the methods enables derived classes to participate in value determination. To avoid potential issues with runtime initialization, you shouldn't set dependency property values within constructors of classes, unless you follow a specific constructor pattern. For more information, see [Safe constructor patterns for DependencyObjects](/dotnet/desktop/wpf/advanced/safe-constructor-patterns-for-dependencyobjects?view=netframeworkdesktop-4.8&preserve-view=true).
## See also
- [Dependency properties overview](dependency-properties-overview.md)
- [Dependency property metadata](/dotnet/desktop/wpf/advanced/dependency-property-metadata?view=netframeworkdesktop-4.8&preserve-view=true)
- [Control authoring overview](/dotnet/desktop/wpf/controls/control-authoring-overview?view=netframeworkdesktop-4.8&preserve-view=true)
- [Collection-type dependency properties](collection-type-dependency-properties.md)
- [Dependency property security](/dotnet/desktop/wpf/advanced/dependency-property-security?view=netframeworkdesktop-4.8&preserve-view=true)
- [XAML loading and dependency properties](/dotnet/desktop/wpf/advanced/xaml-loading-and-dependency-properties?view=netframeworkdesktop-4.8&preserve-view=true)
- [Safe constructor patterns for DependencyObjects](/dotnet/desktop/wpf/advanced/safe-constructor-patterns-for-dependencyobjects?view=netframeworkdesktop-4.8&preserve-view=true)
@@ -0,0 +1,120 @@
---
title: "Dependency property metadata"
description: Learn about dependency property metadata in Windows Presentation Foundation (WPF) and how to create, assign, and override metadata.
ms.date: "11/02/2021"
helpviewer_keywords:
- "APIs [WPF], metadata"
- "dependency properties [WPF], metadata"
- "metadata [WPF], for dependency properties"
- "overriding metadata [WPF]"
---
<!-- The acrolinx score was 92 on 11/02/2021-->
# Dependency property metadata (WPF .NET)
The Windows Presentation Foundation (WPF) property system includes a dependency property metadata reporting system. The information available through the metadata reporting system exceeds what is available through reflection or general common language runtime (CLR) characteristics. When you register a dependency property, you have the option to create and assign metadata to it. If you derive from a class that defines a dependency property, you can override the metadata for the inherited dependency property. And, if you add your class as an owner of a dependency property, you can override the metadata of the inherited dependency property.
## Prerequisites
The article assumes a basic knowledge of dependency properties, and that you've read [Dependency properties overview](dependency-properties-overview.md). To follow the examples in this article, it helps if you're familiar with Extensible Application Markup Language (XAML) and know how to write WPF applications.
## How metadata is used
You can query dependency property metadata to examine the characteristics of a dependency property. When the property system processes a dependency property, it accesses its metadata. The metadata object for a dependency property contains the following types of information:
- The default value of the dependency property, which is set by the property system when no other value applies, such as a local, style, or inheritance value. For more information about value precedence during run-time assignment of dependency property values, see [Dependency property value precedence](dependency-property-value-precedence.md).
- References to coercion value callbacks and property change callbacks on the owner type. You can only obtain references to callbacks that have a `public` access modifier or are within your permitted access scope. For more information about dependency property callbacks, see [Dependency property callbacks and validation](/dotnet/desktop/wpf/advanced/dependency-property-callbacks-and-validation?view=netframeworkdesktop-4.8&preserve-view=true).
- WPF framework-level dependency property characteristics (if the dependency property is a WPF framework property). WPF processes, such as the framework layout engine and the property inheritance logic, query WPF framework-level metadata. For more information, see [Framework property metadata](/dotnet/desktop/wpf/advanced/framework-property-metadata?view=netframeworkdesktop-4.8&preserve-view=true).
## Metadata APIs
The <xref:System.Windows.PropertyMetadata> class stores most of the metadata used by the property system. Metadata instances can be created and assigned by:
- Types that register dependency properties with the property system.
- Types that inherit from a class that defines a dependency property.
- Types that add themselves as an owner of a dependency property.
If a type registers a dependency property without specifying metadata, the property system assigns a `PropertyMetadata` object with default values for that type to the dependency property.
To retrieve metadata for a dependency property, call one of the <xref:System.Windows.DependencyProperty.GetMetadata%2A> overloads on the <xref:System.Windows.DependencyProperty> identifier. The metadata is returned as a `PropertyMetadata` object.
More specific metadata classes, derived from `PropertyMetadata`, exist for different architectural areas. For example, <xref:System.Windows.UIPropertyMetadata> supports animation reporting, and <xref:System.Windows.FrameworkPropertyMetadata> supports WPF framework properties. Dependency properties can also be registered with the `PropertyMetadata` derived classes. Although `GetMetadata` returns a `PropertyMetadata` object, when applicable you can cast to a derived type to examine type-specific properties.
The property characteristics that are exposed by `FrameworkPropertyMetadata` are sometimes referred to as *flags*. When you create a `FrameworkPropertyMetadata` instance, you have the option to pass an instance of the enumeration type <xref:System.Windows.FrameworkPropertyMetadataOptions> into the `FrameworkPropertyMetadata` constructor. `FrameworkPropertyMetadataOptions` lets you specify metadata flags in bitwise combination. The `FrameworkPropertyMetadata` uses `FrameworkPropertyMetadataOptions` to keep the length of its constructor signature reasonable. On dependency property registration, the metadata flags that you set on `FrameworkPropertyMetadataOptions` are exposed within `FrameworkPropertyMetadata` as `Boolean` properties rather than a bitwise combination of flags, to make querying metadata characteristics more intuitive.
## Override or create new metadata?
When you inherit a dependency property, you have the option to change characteristics of the dependency property by overriding its metadata. However, you might not always be able to accomplish your dependency property scenario by overriding metadata, and sometimes it's necessary to define a custom dependency property in your class with new metadata. Custom dependency properties have the same capabilities as dependency properties defined by WPF types. For more information, see [Custom dependency properties](custom-dependency-properties.md).
One characteristic of a dependency property that you can't override is its value type. If an inherited dependency property has the approximate behavior you need, but your scenario requires a different value type, consider implementing a custom dependency property. You might be able to link the property values through type conversion or other implementation in your derived class.
### Scenarios for overriding metadata
Example scenarios for overriding existing dependency property metadata are:
- Changing the default value, which is a common scenario.
- Changing or adding property-change callbacks, which might be necessary if an inherited dependency property interacts with other dependency properties differently than its base implementation does. One of the characteristics of a programming model that supports both code and markup, is that property values might be set in any order. This factor can affect how you implement property-change callbacks. For more information, see [Dependency property callbacks and validation](/dotnet/desktop/wpf/advanced/dependency-property-callbacks-and-validation?view=netframeworkdesktop-4.8&preserve-view=true).
- Changing WPF [framework property metadata](<xref:System.Windows.FrameworkPropertyMetadata>) options. Typically, metadata options are set during registration of a new dependency property, but you can respecify them in <xref:System.Windows.DependencyProperty.OverrideMetadata%2A> or <xref:System.Windows.DependencyProperty.AddOwner%2A> calls. For more information about overriding framework property metadata, see [Specifying metadata](/dotnet/desktop/wpf/advanced/framework-property-metadata?view=netframeworkdesktop-4.8&preserve-view=true#specifying-metadata). For how to set framework property metadata options when registering a dependency property, see [Custom dependency properties](custom-dependency-properties.md).
> [!NOTE]
> Since validation callbacks aren't part of metadata, they can't be changed by overriding metadata. For more information, see [Validation callbacks](/dotnet/desktop/wpf/advanced/dependency-property-callbacks-and-validation?view=netframeworkdesktop-4.8&preserve-view=true#validation-callbacks).
## Overriding metadata
When implementing a new dependency property, you can set its metadata by using overloads of the <xref:System.Windows.DependencyProperty.Register%2A> method. If your class inherits a dependency property, you can override inherited metadata values using the <xref:System.Windows.DependencyProperty.OverrideMetadata%2A> method. For example, you might use `OverrideMetadata` to set type-specific values. For more information and code samples, see [Override metadata for a dependency property](/dotnet/desktop/wpf/advanced/how-to-override-metadata-for-a-dependency-property?view=netframeworkdesktop-4.8&preserve-view=true).
An example of a WPF dependency property, is <xref:System.Windows.UIElement.Focusable%2A>. The <xref:System.Windows.FrameworkElement> class registers `Focusable`. The <xref:System.Windows.Controls.Control> class derives from `FrameworkElement`, inherits the `Focusable` dependency property, and overrides the inherited property metadata. The override changes the default property value from `false` to `true`, but preserves other inherited metadata values.
Since most existing dependency properties aren't virtual properties, their inherited implementation shadows the existing member. When you override a metadata characteristic, the new metadata value either replaces the original value or they're merged:
- For a <xref:System.Windows.PropertyMetadata.DefaultValue%2A>, the new value will replace the existing default value. If you don't specify a `DefaultValue` in the override metadata, the value comes from the nearest ancestor that specified `DefaultValue` in metadata.
- For a <xref:System.Windows.PropertyMetadata.PropertyChangedCallback%2A>, the default merge logic stores all `PropertyChangedCallback` values in a table, and all are invoked on a property change. The callback order is determined by class depth, where the callback registered by the base class in the hierarchy runs first.
- For a <xref:System.Windows.PropertyMetadata.CoerceValueCallback%2A>, the new value will replace the existing `CoerceValueCallback` value. If you don't specify a `CoerceValueCallback` in the override metadata, the value comes from the nearest ancestor that specified `CoerceValueCallback` in metadata.
> [!NOTE]
> The default merge logic is implemented by the <xref:System.Windows.PropertyMetadata.Merge%2A> method. You can specify custom merge logic in a derived class that inherits a dependency property, by overriding `Merge` in that class.
## Add a class as an owner
To "inherit" a dependency property that's registered in a different class hierarchy, use the <xref:System.Windows.DependencyProperty.AddOwner%2A> method. This method is typically used when the adding class isn't derived from the type that registered the dependency property. In the `AddOwner` call, the adding class can create and assign type-specific metadata for the inherited dependency property. To be a full participant in the property system, through code and markup, the adding class should implement these public members:
- A dependency property identifier field. The value of the dependency property identifier is the return value of the `AddOwner` call. This field should be a `public static readonly` field of type <xref:System.Windows.DependencyProperty>.
- A CLR wrapper that implements `get` and `set` accessors. By using a property wrapper, consumers of dependency properties can get or set dependency property values, just as they would any other CLR property. The `get` and `set` accessors interact with the underlying property system through <xref:System.Windows.DependencyObject.GetValue%2A?displayProperty=nameWithType> and <xref:System.Windows.DependencyObject.SetValue%2A?displayProperty=nameWithType> calls, passing in the dependency property identifier as a parameter. Implement the wrapper the same way you would when registering a custom dependency property. For more information, see [Custom dependency properties](custom-dependency-properties.md)
A class that calls `AddOwner` has the same requirements for exposing the object model of the inherited dependency property as a class that defines a new custom dependency property. For more information, see [Add an owner type for a dependency property](/dotnet/desktop/wpf/advanced/how-to-add-an-owner-type-for-a-dependency-property?view=netframeworkdesktop-4.8&preserve-view=true).
## Attached property metadata
In WPF, most UI-related attached properties on WPF types are implemented as dependency properties. Attached properties implemented as dependency properties support dependency property concepts, such as metadata that derived classes can override. Metadata for an attached property is generally no different than for a dependency property. You can override the default value, property change callbacks, and WPF framework properties for the inherited attached property, on instances of the overriding class. For more information, see [Attached property metadata](attached-properties-overview.md)
> [!NOTE]
> Always use <xref:System.Windows.DependencyProperty.RegisterAttached%2A> to register properties where you specify <xref:System.Windows.FrameworkPropertyMetadata.Inherits%2A> in the metadata. Although property value inheritance might appear to work for nonattached dependency properties, the value inheritance behavior for a nonattached property through certain object-object divisions in the runtime tree is undefined. The `Inherits` property isn't relevant for nonattached properties. For more information, see <xref:System.Windows.DependencyProperty.RegisterAttached(System.String,System.Type,System.Type,System.Windows.PropertyMetadata)>, and the remarks section of <xref:System.Windows.FrameworkPropertyMetadata.Inherits%2A>.
### Add a class as owner of an attached property
To inherit an attached property from another class, but expose it as a nonattached dependency property on your class:
- Call <xref:System.Windows.DependencyProperty.AddOwner%2A> to add your class as an owner of the attached dependency property.
- Assign the return value of the `AddOwner` call to a `public static readonly` field, for use as the dependency property identifier.
- Define a CLR wrapper, which adds the property as a class member and supports nonattached property usage.
## See also
- <xref:System.Windows.PropertyMetadata>
- <xref:System.Windows.DependencyObject>
- <xref:System.Windows.DependencyProperty>
- <xref:System.Windows.DependencyProperty.GetMetadata%2A>
- <xref:System.Windows.DependencyProperty.AddOwner%2A>
- [Dependency properties overview](dependency-properties-overview.md)
- [Framework property metadata](/dotnet/desktop/wpf/advanced/framework-property-metadata?view=netframeworkdesktop-4.8&preserve-view=true)
@@ -0,0 +1,39 @@
---
title: "How to override metadata for a dependency property"
description: "Learn how to override a dependency property in Windows Presentation Foundation (WPF) by calling the OverrideMetadata method."
ms.date: "11/04/2021"
dev_langs:
- "csharp"
- "vb"
helpviewer_keywords:
- "metadata [WPF], overriding for dependency properties"
- "dependency properties [WPF], overriding metadata for"
- "overriding metadata for dependency properties [WPF]"
---
<!-- The acrolinx score was 92 on 11/04/2021-->
# How to override metadata for a dependency property (WPF .NET)
When you derive from a class that defines a dependency property, you inherit the dependency property and its metadata. This article describes how you can override the metadata of an inherited dependency property by calling the <xref:System.Windows.DependencyProperty.OverrideMetadata%2A> method. Overriding the metadata lets you modify characteristics of the inherited dependency property to match subclass-specific requirements.
## Background
A class that defines a dependency property can specify its characteristics in <xref:System.Windows.PropertyMetadata> or one of its derived types, such as <xref:System.Windows.FrameworkPropertyMetadata>. Examples of those characteristics are the default value and callback references that trigger on property change and/or coercion value change. Many classes that define dependency properties, specify property metadata during dependency property registration. When metadata isn't specified during registration, the WPF property system assigns a `PropertyMetadata` object with default values. Derived classes that inherit dependency properties through class inheritance have the option to override the original metadata of any dependency property. In this way, derived classes can selectively modify dependency property characteristics to meet class requirements. When calling <xref:System.Windows.DependencyProperty.OverrideMetadata(System.Type,System.Windows.PropertyMetadata)>, a derived class specifies its own type as the first parameter, and a metadata instance as the second parameter.
A derived class that overrides metadata on a dependency property must do so before the property is placed in use by the property system. A dependency property is placed in use when any instance of the class that registers the property is instantiated. To help meet this requirement, the derived class should call <xref:System.Windows.DependencyProperty.OverrideMetadata%2A> within its static constructor. Overriding the metadata of a dependency property after its owner type is instantiated won't raise exceptions, but will result in inconsistent behaviors in the property system. Also, a derived type can't override the metadata of a dependency property more than once, and attempts to do so will raise an exception.
## Example
In the following example, the derived class `TropicalAquarium` overrides the metadata of a dependency property inherited from the base class `Aquarium`. The metadata type is <xref:System.Windows.FrameworkPropertyMetadata>, which supports UI-related WPF framework characteristics such as <xref:System.Windows.FrameworkPropertyMetadataOptions.AffectsRender>. The derived class doesn't override the inherited `AffectsRender` flag, but it does update the default value of `AquariumGraphic` on derived class instances.
:::code language="csharp" source="./snippets/how-to-override-metadata-for-a-dependency-property/csharp/MainWindow.xaml.cs" id="BaseDependencyProperty":::
:::code language="vb" source="./snippets/how-to-override-metadata-for-a-dependency-property/vb/MainWindow.xaml.vb" id="BaseDependencyProperty":::
:::code language="csharp" source="./snippets/how-to-override-metadata-for-a-dependency-property/csharp/MainWindow.xaml.cs" id="InheritedDependencyProperty":::
:::code language="vb" source="./snippets/how-to-override-metadata-for-a-dependency-property/vb/MainWindow.xaml.vb" id="InheritedDependencyProperty":::
## See also
- <xref:System.Windows.DependencyProperty>
- [Dependency property metadata](dependency-property-metadata.md)
- [Dependency properties overview](dependency-properties-overview.md)
- [Custom dependency properties](custom-dependency-properties.md)
@@ -69,20 +69,17 @@ namespace CodeSampleCsharp
public class Aquarium : DependencyObject
{
// Register a dependency property with the specified property name,
// property type, and owner type.
private static readonly DependencyProperty s_aquariumContentsProperty =
// property type, and owner type. Store the dependency property
// identifier as a public static readonly member of the class.
public static readonly DependencyProperty AquariumContentsProperty =
DependencyProperty.Register(
name: "AquariumContents",
propertyType: typeof(List<FrameworkElement>),
ownerType: typeof(Aquarium)
);
// Store the dependency property identifier as a static member of the class.
public static readonly DependencyProperty AquariumContentsProperty =
s_aquariumContentsProperty;
// Set the default collection value in a class constructor.
public Aquarium() => SetValue(s_aquariumContentsProperty, new List<FrameworkElement>());
public Aquarium() => SetValue(AquariumContentsProperty, new List<FrameworkElement>());
// Declare a read-write property.
public List<FrameworkElement> AquariumContents
@@ -76,20 +76,17 @@
Inherits DependencyObject
' Register a dependency property with the specified property name,
' property type, and owner type.
Private Shared ReadOnly s_aquariumContentsProperty As DependencyProperty =
' property type, and owner type. Store the dependency property
' identifier as a static member of the class.
Public Shared ReadOnly AquariumContentsProperty As DependencyProperty =
DependencyProperty.Register(
name:="AquariumContents",
propertyType:=GetType(List(Of FrameworkElement)),
ownerType:=GetType(Aquarium))
' Store the dependency property identifier as a static member of the class.
Public Shared ReadOnly AquariumContentsProperty As DependencyProperty =
s_aquariumContentsProperty
' Set the default collection value in a class constructor.
Public Sub New()
SetValue(s_aquariumContentsProperty, New List(Of FrameworkElement)())
SetValue(AquariumContentsProperty, New List(Of FrameworkElement)())
End Sub
' Declare a read-write property.
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
namespace CodeSampleCsharp
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
}
}
@@ -0,0 +1,10 @@
using System.Windows;
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net5.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
</Project>
@@ -0,0 +1,5 @@
<Window x:Class="CodeSampleCsharp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:src="clr-namespace:CodeSampleCsharp"
Title="Custom Dependency Properties" Height="100" Width="400">
</Window>
@@ -0,0 +1,49 @@
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace CodeSampleCsharp
{
/// <summary>
/// Interaction logic for MainWindow.xaml.
/// </summary>
public partial class MainWindow : Window
{
}
public class Aquarium : DependencyObject
{
//<RegisterDependencyPropertyWithWrapper>
//<RegisterDependencyProperty>
// Register a dependency property with the specified property name,
// property type, owner type, and property metadata. Store the dependency
// property identifier as a public static readonly member of the class.
public static readonly DependencyProperty AquariumGraphicProperty =
DependencyProperty.Register(
name: "AquariumGraphic",
propertyType: typeof(Uri),
ownerType: typeof(Aquarium),
typeMetadata: new FrameworkPropertyMetadata(
defaultValue: new Uri("http://www.contoso.com/aquarium-graphic.jpg"),
flags: FrameworkPropertyMetadataOptions.AffectsRender,
propertyChangedCallback: new PropertyChangedCallback(OnUriChanged))
);
//</RegisterDependencyProperty>
// Declare a read-write property.
public Uri AquariumGraphic
{
get => (Uri)GetValue(AquariumGraphicProperty);
set => SetValue(AquariumGraphicProperty, value);
}
//</RegisterDependencyPropertyWithWrapper>
private static void OnUriChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
Shape shape = (Shape)dependencyObject;
shape.Fill = new ImageBrush(new BitmapImage((Uri)e.NewValue));
}
}
}
@@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace CodeSampleCsharp.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CodeSampleCsharp.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
@@ -0,0 +1,9 @@
<Application x:Class="CodeSampleCsharp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CodeSampleCsharp"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>
@@ -0,0 +1,9 @@
<Application x:Class="Application"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CodeSampleVb"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>
@@ -0,0 +1,6 @@
Class Application
' Application-level events, such as Startup, Exit, and DispatcherUnhandledException
' can be handled in this file.
End Class
@@ -0,0 +1,11 @@
Imports System.Windows
'The ThemeInfo attribute describes where any theme specific and generic resource dictionaries can be found.
'1st parameter: where theme specific resource dictionaries are located
'(used if a resource is not found in the page,
' or application resource dictionaries)
'2nd parameter: where the generic resource dictionary is located
'(used if a resource is not found in the page,
'app, and any theme specific resource dictionaries)
<Assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)>
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net5.0-windows</TargetFramework>
<RootNamespace>CodeSampleVb</RootNamespace>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<Import Include="System.Windows" />
<Import Include="System.Windows.Controls" />
<Import Include="System.Windows.Data" />
<Import Include="System.Windows.Documents" />
<Import Include="System.Windows.Input" />
<Import Include="System.Windows.Media" />
<Import Include="System.Windows.Media.Imaging" />
<Import Include="System.Windows.Navigation" />
<Import Include="System.Windows.Shapes" />
</ItemGroup>
</Project>
@@ -0,0 +1,5 @@
<Window x:Class="CodeSampleVb.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:src="clr-namespace:CodeSampleVb"
Title="Custom Dependency Properties" Height="100" Width="400">
</Window>
@@ -0,0 +1,51 @@
Namespace CodeSampleVb
' <summary>
' Interaction logic for MainWindow.xaml.
' </summary>
Partial Public Class MainWindow
Inherits Window
Public Sub New()
InitializeComponent()
End Sub
End Class
Public Class Aquarium
Inherits DependencyObject
'<RegisterDependencyPropertyWithWrapper>
'<RegisterDependencyProperty>
' Register a dependency property with the specified property name,
' property type, owner type, and property metadata. Store the dependency
' property identifier as a public static readonly member of the class.
Public Shared ReadOnly AquariumGraphicProperty As DependencyProperty =
DependencyProperty.Register(
name:="AquariumGraphic",
propertyType:=GetType(Uri),
ownerType:=GetType(Aquarium),
typeMetadata:=New FrameworkPropertyMetadata(
defaultValue:=New Uri("http://www.contoso.com/aquarium-graphic.jpg"),
flags:=FrameworkPropertyMetadataOptions.AffectsRender,
propertyChangedCallback:=New PropertyChangedCallback(AddressOf OnUriChanged)))
'</RegisterDependencyProperty>
' Declare a read-write property.
Public Property AquariumGraphic As Uri
Get
Return CType(GetValue(AquariumGraphicProperty), Uri)
End Get
Set
SetValue(AquariumGraphicProperty, Value)
End Set
End Property
'</RegisterDependencyPropertyWithWrapper>
Private Shared Sub OnUriChanged(dependencyObject As DependencyObject, e As DependencyPropertyChangedEventArgs)
Dim shape As Shape = CType(dependencyObject, Shape)
shape.Fill = New ImageBrush(New BitmapImage(CType(e.NewValue, Uri)))
End Sub
End Class
End Namespace
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
namespace CodeSampleCsharp
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
}
}
@@ -0,0 +1,10 @@
using System.Windows;
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net5.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
</Project>
@@ -0,0 +1,8 @@
<Window x:Class="CodeSampleCsharp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="How to override dependency property metadata" Height="200" Width="800" Loaded="ValidateSnippet">
<Grid>
<Label x:Name="lblMessage" HorizontalAlignment="Stretch" Margin="10" VerticalAlignment="Stretch"/>
</Grid>
</Window>
@@ -0,0 +1,75 @@
using System;
using System.Windows;
namespace CodeSampleCsharp
{
/// <summary>
/// Interaction logic for MainWindow.xaml.
/// </summary>
public partial class MainWindow : Window
{
public MainWindow() => InitializeComponent();
public void ValidateSnippet(object sender, RoutedEventArgs e)
{
TropicalAquarium tropicalAquarium = new();
Aquarium aquarium = new();
FrameworkPropertyMetadata aquariumPropertyMetadata = (FrameworkPropertyMetadata)Aquarium.AquariumGraphicProperty.GetMetadata(aquarium);
FrameworkPropertyMetadata tropicalAquariumPropertyMetadata = (FrameworkPropertyMetadata)Aquarium.AquariumGraphicProperty.GetMetadata(tropicalAquarium);
lblMessage.Content = $"Tropical aquarium graphic URL: " + $"{tropicalAquarium.AquariumGraphic.OriginalString}" + Environment.NewLine;
lblMessage.Content += $"Aquarium graphic URL: " + $"{aquarium.AquariumGraphic.OriginalString}" + Environment.NewLine;
lblMessage.Content += $"Queried owner-type AquariumGraphic default value: " + $"{aquariumPropertyMetadata.DefaultValue}" + Environment.NewLine;
lblMessage.Content += $"Queried owner-type AquariumGraphic affects render: " + $"{aquariumPropertyMetadata.AffectsRender}" + Environment.NewLine;
lblMessage.Content += $"Queried derived-type TropicalAquarium default value: " + $"{tropicalAquariumPropertyMetadata.DefaultValue}" + Environment.NewLine;
lblMessage.Content += $"Queried derived-type TropicalAquarium affects render: " + $"{tropicalAquariumPropertyMetadata.AffectsRender}" + Environment.NewLine;
}
}
//<BaseDependencyProperty>
public class Aquarium : DependencyObject
{
// Register a dependency property with the specified property name,
// property type, owner type, and property metadata.
public static readonly DependencyProperty AquariumGraphicProperty =
DependencyProperty.Register(
name: "AquariumGraphic",
propertyType: typeof(Uri),
ownerType: typeof(Aquarium),
typeMetadata: new FrameworkPropertyMetadata(
defaultValue: new Uri("http://www.contoso.com/aquarium-graphic.jpg"),
flags: FrameworkPropertyMetadataOptions.AffectsRender)
);
// Declare a read-write CLR wrapper with get/set accessors.
public Uri AquariumGraphic
{
get => (Uri)GetValue(AquariumGraphicProperty);
set => SetValue(AquariumGraphicProperty, value);
}
}
//</BaseDependencyProperty>
//<InheritedDependencyProperty>
public class TropicalAquarium : Aquarium
{
// Static constructor.
static TropicalAquarium()
{
// Create a new metadata instance with a modified default value.
FrameworkPropertyMetadata newPropertyMetadata = new(
defaultValue: new Uri("http://www.contoso.com/tropical-aquarium-graphic.jpg"));
// Call OverrideMetadata on the dependency property identifier.
// Pass in the type for which the new metadata will be applied
// and the new metadata instance.
AquariumGraphicProperty.OverrideMetadata(
forType: typeof(TropicalAquarium),
typeMetadata: newPropertyMetadata);
}
}
//</InheritedDependencyProperty>
}
@@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace CodeSampleCsharp.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CodeSampleCsharp.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
@@ -0,0 +1,9 @@
<Application x:Class="CodeSampleCsharp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CodeSampleCsharp"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>
@@ -0,0 +1,9 @@
<Application x:Class="Application"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CodeSampleVb"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>
@@ -0,0 +1,6 @@
Class Application
' Application-level events, such as Startup, Exit, and DispatcherUnhandledException
' can be handled in this file.
End Class
@@ -0,0 +1,11 @@
Imports System.Windows
'The ThemeInfo attribute describes where any theme specific and generic resource dictionaries can be found.
'1st parameter: where theme specific resource dictionaries are located
'(used if a resource is not found in the page,
' or application resource dictionaries)
'2nd parameter: where the generic resource dictionary is located
'(used if a resource is not found in the page,
'app, and any theme specific resource dictionaries)
<Assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)>
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net5.0-windows</TargetFramework>
<RootNamespace>CodeSampleVb</RootNamespace>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<Import Include="System.Windows" />
<Import Include="System.Windows.Controls" />
<Import Include="System.Windows.Data" />
<Import Include="System.Windows.Documents" />
<Import Include="System.Windows.Input" />
<Import Include="System.Windows.Media" />
<Import Include="System.Windows.Media.Imaging" />
<Import Include="System.Windows.Navigation" />
<Import Include="System.Windows.Shapes" />
</ItemGroup>
</Project>
@@ -0,0 +1,8 @@
<Window x:Class="CodeSampleVb.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="How to override dependency property metadata" Height="200" Width="800" Loaded="ValidateSnippet">
<Grid>
<Label x:Name="lblMessage" HorizontalAlignment="Stretch" Margin="10" VerticalAlignment="Stretch"/>
</Grid>
</Window>
@@ -0,0 +1,81 @@
Namespace CodeSampleVb
' <summary>
' Interaction logic for MainWindow.xaml.
' </summary>
Partial Public Class MainWindow
Inherits Window
Public Sub New()
InitializeComponent()
End Sub
Public Sub ValidateSnippet(sender As Object, e As RoutedEventArgs)
Dim tropicalAquarium As New TropicalAquarium()
Dim aquarium As New Aquarium()
Dim aquariumPropertyMetadata As FrameworkPropertyMetadata = CType(Aquarium.AquariumGraphicProperty.GetMetadata(aquarium), FrameworkPropertyMetadata)
Dim tropicalAquariumPropertyMetadata As FrameworkPropertyMetadata = CType(Aquarium.AquariumGraphicProperty.GetMetadata(tropicalAquarium), FrameworkPropertyMetadata)
lblMessage.Content = $"Tropical aquarium graphic URL: {tropicalAquarium.AquariumGraphic.OriginalString}" & Environment.NewLine
lblMessage.Content += $"Aquarium graphic URL: {aquarium.AquariumGraphic.OriginalString}" & Environment.NewLine
lblMessage.Content += $"Queried owner-type AquariumGraphic default value: {aquariumPropertyMetadata.DefaultValue}" & Environment.NewLine
lblMessage.Content += $"Queried owner-type AquariumGraphic affects render: {aquariumPropertyMetadata.AffectsRender}" & Environment.NewLine
lblMessage.Content += $"Queried derived-type TropicalAquarium default value: {tropicalAquariumPropertyMetadata.DefaultValue}" & Environment.NewLine
lblMessage.Content += $"Queried derived-type TropicalAquarium affects render: {tropicalAquariumPropertyMetadata.AffectsRender}" & Environment.NewLine
End Sub
End Class
'<BaseDependencyProperty>
Public Class Aquarium
Inherits DependencyObject
' Register a dependency property with the specified property name,
' property type, owner type, and property metadata.
Public Shared ReadOnly AquariumGraphicProperty As DependencyProperty =
DependencyProperty.Register(
name:="AquariumGraphic",
propertyType:=GetType(Uri),
ownerType:=GetType(Aquarium),
typeMetadata:=New FrameworkPropertyMetadata(
defaultValue:=New Uri("http://www.contoso.com/aquarium-graphic.jpg"),
flags:=FrameworkPropertyMetadataOptions.AffectsRender))
' Declare a read-write CLR wrapper with get/set accessors.
Public Property AquariumGraphic As Uri
Get
Return CType(GetValue(AquariumGraphicProperty), Uri)
End Get
Set
SetValue(AquariumGraphicProperty, Value)
End Set
End Property
End Class
'</BaseDependencyProperty>
'<InheritedDependencyProperty>
Public Class TropicalAquarium
Inherits Aquarium
' Static constructor.
Shared Sub New()
' Create a new metadata instance with a modified default value.
Dim newPropertyMetadata As New FrameworkPropertyMetadata(
defaultValue:=New Uri("http://www.contoso.com/tropical-aquarium-graphic.jpg"))
' Call OverrideMetadata on the dependency property identifier.
' Pass in the type for which the new metadata will be applied
' and the new metadata instance.
AquariumGraphicProperty.OverrideMetadata(
forType:=GetType(TropicalAquarium),
typeMetadata:=newPropertyMetadata)
End Sub
End Class
'</InheritedDependencyProperty>
End Namespace
+6
View File
@@ -88,12 +88,18 @@ items:
href: properties/attached-properties-overview.md
- name: Collection-type dependency properties
href: properties/collection-type-dependency-properties.md
- name: Custom dependency properties
href: properties/custom-dependency-properties.md
- name: Dependency property metadata
href: properties/dependency-property-metadata.md
- name: Common tasks
items:
- name: Implement a dependency property
href: properties/how-to-implement-a-dependency-property.md
- name: Register an attached property
href: properties/how-to-register-an-attached-property.md
- name: Override dependency property metadata
href: properties/how-to-override-metadata-for-a-dependency-property.md
- name: Resources
items:
- name: Overview
+15
View File
@@ -349,6 +349,21 @@
"SourceUrl": "/dotnet/desktop/wpf/advanced/how-to-implement-a-dependency-property?view=netframeworkdesktop-4.8",
"TargetUrl": "/dotnet/desktop/wpf/properties/how-to-implement-a-dependency-property?view=netdesktop-5.0"
},
{
"Redirect": "TwoWay",
"SourceUrl": "/dotnet/desktop/wpf/advanced/custom-dependency-properties?view=netframeworkdesktop-4.8",
"TargetUrl": "/dotnet/desktop/wpf/properties/custom-dependency-properties?view=netdesktop-5.0"
},
{
"Redirect": "TwoWay",
"SourceUrl": "/dotnet/desktop/wpf/advanced/dependency-property-metadata?view=netframeworkdesktop-4.8",
"TargetUrl": "/dotnet/desktop/wpf/properties/dependency-property-metadata?view=netdesktop-5.0"
},
{
"Redirect": "TwoWay",
"SourceUrl": "/dotnet/desktop/wpf/advanced/how-to-override-metadata-for-a-dependency-property?view=netframeworkdesktop-4.8",
"TargetUrl": "/dotnet/desktop/wpf/properties/how-to-override-metadata-for-a-dependency-property?view=netdesktop-5.0"
},
// Systems - XAML
{