From 58f6e05c13347e27cd801b9bb066bcb3dad17bfa Mon Sep 17 00:00:00 2001 From: Tris Shores <86677757+v-trisshores@users.noreply.github.com> Date: Wed, 5 Jan 2022 11:01:06 -0600 Subject: [PATCH 1/3] Add desktop-guide note to all WPF property articles (#1258) --- .../net/wpf/properties/attached-properties-overview.md | 2 ++ .../wpf/properties/collection-type-dependency-properties.md | 6 ++++++ .../net/wpf/properties/custom-dependency-properties.md | 2 ++ .../dependency-property-callbacks-and-validation.md | 2 ++ .../net/wpf/properties/dependency-property-metadata.md | 2 ++ .../wpf/properties/dependency-property-value-precedence.md | 2 ++ .../properties/how-to-implement-a-dependency-property.md | 4 +++- .../how-to-override-metadata-for-a-dependency-property.md | 2 ++ .../wpf/properties/how-to-register-an-attached-property.md | 2 ++ 9 files changed, 23 insertions(+), 1 deletion(-) diff --git a/dotnet-desktop-guide/net/wpf/properties/attached-properties-overview.md b/dotnet-desktop-guide/net/wpf/properties/attached-properties-overview.md index d1690430a7..12323bd191 100644 --- a/dotnet-desktop-guide/net/wpf/properties/attached-properties-overview.md +++ b/dotnet-desktop-guide/net/wpf/properties/attached-properties-overview.md @@ -15,6 +15,8 @@ helpviewer_keywords: An attached property is a Extensible Application Markup Language (XAML) concept. Attached properties enable extra property/value pairs to be set on any XAML element, even though the element doesn't define those extra properties in its object model. The extra properties are globally accessible. Attached properties are typically defined as a specialized form of dependency property that doesn't have a conventional property wrapper. +[!INCLUDE [desktop guide under construction](../../includes/desktop-guide-preview-note.md)] + ## 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 XAML and know how to write Windows Presentation Foundation (WPF) applications. diff --git a/dotnet-desktop-guide/net/wpf/properties/collection-type-dependency-properties.md b/dotnet-desktop-guide/net/wpf/properties/collection-type-dependency-properties.md index 2a0e88f8d9..d7d1de9775 100644 --- a/dotnet-desktop-guide/net/wpf/properties/collection-type-dependency-properties.md +++ b/dotnet-desktop-guide/net/wpf/properties/collection-type-dependency-properties.md @@ -17,6 +17,12 @@ helpviewer_keywords: This article provides guidance and suggested patterns for implementing a dependency property that's a collection type. +[!INCLUDE [desktop guide under construction](../../includes/desktop-guide-preview-note.md)] + +## 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. + ## Implement a collection-type dependency property In general, the implementation pattern for a dependency property is a CLR property wrapper backed by a identifier instead of a field or other construct. You can follow the same pattern when you implement a collection-type dependency property. The pattern is more complex if the collection element type is a or a derived class. diff --git a/dotnet-desktop-guide/net/wpf/properties/custom-dependency-properties.md b/dotnet-desktop-guide/net/wpf/properties/custom-dependency-properties.md index 9aec98d447..7743be0610 100644 --- a/dotnet-desktop-guide/net/wpf/properties/custom-dependency-properties.md +++ b/dotnet-desktop-guide/net/wpf/properties/custom-dependency-properties.md @@ -22,6 +22,8 @@ helpviewer_keywords: 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. , , and 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. +[!INCLUDE [desktop guide under construction](../../includes/desktop-guide-preview-note.md)] + ## 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. diff --git a/dotnet-desktop-guide/net/wpf/properties/dependency-property-callbacks-and-validation.md b/dotnet-desktop-guide/net/wpf/properties/dependency-property-callbacks-and-validation.md index d7b77b8e45..2b158a2a91 100644 --- a/dotnet-desktop-guide/net/wpf/properties/dependency-property-callbacks-and-validation.md +++ b/dotnet-desktop-guide/net/wpf/properties/dependency-property-callbacks-and-validation.md @@ -18,6 +18,8 @@ helpviewer_keywords: This article describes how to define a dependency property and implement dependency property callbacks. The callbacks support value validation, value coercion, and other logic that's needed when a property value changes. +[!INCLUDE [desktop guide under construction](../../includes/desktop-guide-preview-note.md)] + ## 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. diff --git a/dotnet-desktop-guide/net/wpf/properties/dependency-property-metadata.md b/dotnet-desktop-guide/net/wpf/properties/dependency-property-metadata.md index bff2d7f424..07acb4396b 100644 --- a/dotnet-desktop-guide/net/wpf/properties/dependency-property-metadata.md +++ b/dotnet-desktop-guide/net/wpf/properties/dependency-property-metadata.md @@ -14,6 +14,8 @@ helpviewer_keywords: 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. +[!INCLUDE [desktop guide under construction](../../includes/desktop-guide-preview-note.md)] + ## 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. diff --git a/dotnet-desktop-guide/net/wpf/properties/dependency-property-value-precedence.md b/dotnet-desktop-guide/net/wpf/properties/dependency-property-value-precedence.md index 88ffa804aa..c5b956cb08 100644 --- a/dotnet-desktop-guide/net/wpf/properties/dependency-property-value-precedence.md +++ b/dotnet-desktop-guide/net/wpf/properties/dependency-property-value-precedence.md @@ -14,6 +14,8 @@ helpviewer_keywords: The workings of the Windows Presentation Foundation (WPF) property system affect the value of a dependency property. This article explains how the precedence of different property-based inputs within the WPF property system determines the effective value of a dependency property. +[!INCLUDE [desktop guide under construction](../../includes/desktop-guide-preview-note.md)] + ## 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. diff --git a/dotnet-desktop-guide/net/wpf/properties/how-to-implement-a-dependency-property.md b/dotnet-desktop-guide/net/wpf/properties/how-to-implement-a-dependency-property.md index afe80eb6fc..6476b49af0 100644 --- a/dotnet-desktop-guide/net/wpf/properties/how-to-implement-a-dependency-property.md +++ b/dotnet-desktop-guide/net/wpf/properties/how-to-implement-a-dependency-property.md @@ -14,7 +14,9 @@ helpviewer_keywords: # How to implement a dependency property (WPF .NET) This article describes how to implement a dependency property by using a field to back a common language runtime (CLR) property. Dependency properties support several advanced Windows Presentation Foundation (WPF) property system features. These features include styles, data binding, inheritance, animation, and default values. If you want properties that you define to support those features, then implement your properties as a dependency property. - + +[!INCLUDE [desktop guide under construction](../../includes/desktop-guide-preview-note.md)] + ## Example The following example shows how to register a dependency property, by calling the method. The `Register` method returns a instance called a *dependency property identifier*. The identifier is stored in a `static readonly` field, and holds the name and characteristics of a dependency property. diff --git a/dotnet-desktop-guide/net/wpf/properties/how-to-override-metadata-for-a-dependency-property.md b/dotnet-desktop-guide/net/wpf/properties/how-to-override-metadata-for-a-dependency-property.md index 6bbb81dd88..913d22be2f 100644 --- a/dotnet-desktop-guide/net/wpf/properties/how-to-override-metadata-for-a-dependency-property.md +++ b/dotnet-desktop-guide/net/wpf/properties/how-to-override-metadata-for-a-dependency-property.md @@ -16,6 +16,8 @@ helpviewer_keywords: 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 method. Overriding the metadata lets you modify characteristics of the inherited dependency property to match subclass-specific requirements. +[!INCLUDE [desktop guide under construction](../../includes/desktop-guide-preview-note.md)] + ## Background A class that defines a dependency property can specify its characteristics in or one of its derived types, such as . One of those characteristics is the default value of a dependency property. 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 , a derived class specifies its own type as the first parameter, and a metadata instance as the second parameter. diff --git a/dotnet-desktop-guide/net/wpf/properties/how-to-register-an-attached-property.md b/dotnet-desktop-guide/net/wpf/properties/how-to-register-an-attached-property.md index 94396cdb6c..1a7cd74815 100644 --- a/dotnet-desktop-guide/net/wpf/properties/how-to-register-an-attached-property.md +++ b/dotnet-desktop-guide/net/wpf/properties/how-to-register-an-attached-property.md @@ -15,6 +15,8 @@ helpviewer_keywords: This article describes how to register an attached property and provide public accessors that let you access the attached property through Extensible Application Markup Language (XAML) and code. Attached properties enable extra property/value pairs to be set on any XAML element, even though the element doesn't define those extra properties in its object model. The extra properties are globally accessible. Attached properties are typically defined as a specialized form of dependency property that doesn't have a conventional property wrapper. Most attached properties for Windows Presentation Foundation (WPF) types are also implemented as dependency properties. You can create dependency properties on any derived type. +[!INCLUDE [desktop guide under construction](../../includes/desktop-guide-preview-note.md)] + ## Example The following example shows how to register an attached property as a dependency property, by using the method. The provider class has the option of specifying a default value in property metadata. For more information on property metadata, see [Property metadata for a new dependency property](/dotnet/desktop/wpf/advanced/custom-dependency-properties?view=netframeworkdesktop-4.8&preserve-view=true#property-metadata-for-a-new-dependency-property). In this example, the `HasFish` property has a value type, with its default value set to `false`. From cf371fba4c4afcc0861e3bcf9e53411320e3e9ac Mon Sep 17 00:00:00 2001 From: Tris Shores <86677757+v-trisshores@users.noreply.github.com> Date: Wed, 5 Jan 2022 16:43:43 -0600 Subject: [PATCH 2/3] Content update - XAML loading and dependency properties (user story 1878471) (#1257) * Add article, toc, and redirects * Add info on use of a callback to run custom logic and resolve merge conflicts --- .openpublishing.redirection.json | 8 ++ .../csharp/MainWindow.xaml.cs | 23 +++- .../vb/MainWindow.xaml.vb | 16 ++- .../csharp/App.xaml.cs | 17 +++ .../csharp/AssemblyInfo.cs | 10 ++ .../csharp/CodeSampleCsharp.csproj | 25 ++++ .../csharp/MainWindow.xaml | 5 + .../csharp/MainWindow.xaml.cs | 61 +++++++++ .../csharp/Properties/Resources.Designer.cs | 63 +++++++++ .../csharp/Properties/Resources.resx | 120 ++++++++++++++++++ .../csharp/app.xaml | 9 ++ .../vb/Application.xaml | 9 ++ .../vb/Application.xaml.vb | 6 + .../vb/AssemblyInfo.vb | 11 ++ .../vb/CodeSampleVb.vbproj | 22 ++++ .../vb/MainWindow.xaml | 5 + .../vb/MainWindow.xaml.vb | 62 +++++++++ .../xaml-loading-and-dependency-properties.md | 56 ++++++++ dotnet-desktop-guide/net/wpf/toc.yml | 2 + redirects_generator/definitions.json | 4 + 20 files changed, 525 insertions(+), 9 deletions(-) create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/csharp/App.xaml.cs create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/csharp/AssemblyInfo.cs create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/csharp/CodeSampleCsharp.csproj create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/csharp/MainWindow.xaml create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/csharp/MainWindow.xaml.cs create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/csharp/Properties/Resources.Designer.cs create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/csharp/Properties/Resources.resx create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/csharp/app.xaml create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/vb/Application.xaml create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/vb/Application.xaml.vb create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/vb/AssemblyInfo.vb create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/vb/CodeSampleVb.vbproj create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/vb/MainWindow.xaml create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/vb/MainWindow.xaml.vb create mode 100644 dotnet-desktop-guide/net/wpf/properties/xaml-loading-and-dependency-properties.md diff --git a/.openpublishing.redirection.json b/.openpublishing.redirection.json index d408defd52..958fc6daf3 100644 --- a/.openpublishing.redirection.json +++ b/.openpublishing.redirection.json @@ -588,6 +588,14 @@ { "source_path": "dotnet-desktop-guide/framework/wpf/properties/safe-constructor-patterns-for-dependencyobjects.md", "redirect_url": "/dotnet/desktop/wpf/advanced/safe-constructor-patterns-for-dependencyobjects?view=netframeworkdesktop-4.8" + }, + { + "source_path": "dotnet-desktop-guide/net/wpf/advanced/xaml-loading-and-dependency-properties.md", + "redirect_url": "/dotnet/desktop/wpf/properties/xaml-loading-and-dependency-properties?view=netdesktop-6.0" + }, + { + "source_path": "dotnet-desktop-guide/framework/wpf/properties/xaml-loading-and-dependency-properties.md", + "redirect_url": "/dotnet/desktop/wpf/advanced/xaml-loading-and-dependency-properties?view=netframeworkdesktop-4.8" } ] } diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/custom-dependency-properties/csharp/MainWindow.xaml.cs b/dotnet-desktop-guide/net/wpf/properties/snippets/custom-dependency-properties/csharp/MainWindow.xaml.cs index 8ac43f851a..53804a7777 100644 --- a/dotnet-desktop-guide/net/wpf/properties/snippets/custom-dependency-properties/csharp/MainWindow.xaml.cs +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/custom-dependency-properties/csharp/MainWindow.xaml.cs @@ -1,8 +1,6 @@ using System; +using System.Diagnostics; using System.Windows; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Shapes; namespace CodeSampleCsharp { @@ -11,6 +9,19 @@ namespace CodeSampleCsharp /// public partial class MainWindow : Window { + public MainWindow() + { + InitializeComponent(); + + // Test code. + Aquarium aquarium = new(); + aquarium.AquariumGraphic = new Uri("http://www.contoso.com/aquarium-graphic-new.jpg"); + Debug.WriteLine($"Aquarium graphic: {aquarium.AquariumGraphic}"); + + // Output: + // OnUriChanged: http://www.contoso.com/aquarium-graphic-new.jpg + // Aquarium graphic: http://www.contoso.com/aquarium-graphic-new.jpg + } } public class Aquarium : DependencyObject @@ -32,7 +43,7 @@ public class Aquarium : DependencyObject ); // - // Declare a read-write property. + // Declare a read-write property wrapper. public Uri AquariumGraphic { get => (Uri)GetValue(AquariumGraphicProperty); @@ -42,8 +53,8 @@ public Uri AquariumGraphic private static void OnUriChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) { - Shape shape = (Shape)dependencyObject; - shape.Fill = new ImageBrush(new BitmapImage((Uri)e.NewValue)); + Uri value = (Uri)dependencyObject.GetValue(AquariumGraphicProperty); + Debug.WriteLine($"OnUriChanged: {value}"); } } } diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/custom-dependency-properties/vb/MainWindow.xaml.vb b/dotnet-desktop-guide/net/wpf/properties/snippets/custom-dependency-properties/vb/MainWindow.xaml.vb index 7112b454f4..8918b603a6 100644 --- a/dotnet-desktop-guide/net/wpf/properties/snippets/custom-dependency-properties/vb/MainWindow.xaml.vb +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/custom-dependency-properties/vb/MainWindow.xaml.vb @@ -8,7 +8,17 @@ Public Sub New() InitializeComponent() + + ' Test code. + Dim aquarium As New Aquarium With { + .AquariumGraphic = New Uri("http://www.contoso.com/aquarium-graphic-new.jpg") + } + Debug.WriteLine($"Aquarium graphic: {aquarium.AquariumGraphic}") End Sub + + ' Output: + ' OnUriChanged http://www.contoso.com/aquarium-graphic-new.jpg + ' Aquarium graphic: http://www.contoso.com/aquarium-graphic-new.jpg End Class Public Class Aquarium @@ -30,7 +40,7 @@ propertyChangedCallback:=New PropertyChangedCallback(AddressOf OnUriChanged))) ' - ' Declare a read-write property. + ' Declare a read-write property wrapper. Public Property AquariumGraphic As Uri Get Return CType(GetValue(AquariumGraphicProperty), Uri) @@ -42,8 +52,8 @@ ' 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))) + Dim value As Uri = CType(dependencyObject.GetValue(AquariumGraphicProperty), Uri) + Debug.WriteLine($"OnUriChanged: {value}") End Sub End Class diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/csharp/App.xaml.cs b/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/csharp/App.xaml.cs new file mode 100644 index 0000000000..31285520b3 --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/csharp/App.xaml.cs @@ -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 +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/csharp/AssemblyInfo.cs b/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/csharp/AssemblyInfo.cs new file mode 100644 index 0000000000..8b5504ecfb --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/csharp/AssemblyInfo.cs @@ -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) +)] diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/csharp/CodeSampleCsharp.csproj b/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/csharp/CodeSampleCsharp.csproj new file mode 100644 index 0000000000..7cb6479eb6 --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/csharp/CodeSampleCsharp.csproj @@ -0,0 +1,25 @@ + + + + WinExe + net6.0-windows + true + en-US + + + + + True + True + Resources.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/csharp/MainWindow.xaml b/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/csharp/MainWindow.xaml new file mode 100644 index 0000000000..b6e798672e --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/csharp/MainWindow.xaml @@ -0,0 +1,5 @@ + + diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/csharp/MainWindow.xaml.cs b/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/csharp/MainWindow.xaml.cs new file mode 100644 index 0000000000..43e6ad6b1b --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/csharp/MainWindow.xaml.cs @@ -0,0 +1,61 @@ +using System; +using System.Diagnostics; +using System.Windows; + +namespace CodeSampleCsharp +{ + /// + /// Interaction logic for MainWindow.xaml. + /// + public partial class MainWindow : Window + { + public MainWindow() + { + InitializeComponent(); + + // Test code. + Aquarium aquarium = new(); + aquarium.AquariumGraphic = new Uri("http://www.contoso.com/aquarium-graphic-new.jpg"); + Debug.WriteLine($"Aquarium graphic: {aquarium.AquariumGraphic}"); + + // Output: + // OnUriChanged: http://www.contoso.com/aquarium-graphic-new.jpg + // Aquarium graphic: http://www.contoso.com/aquarium-graphic-new.jpg + } + } + + public class Aquarium : DependencyObject + { + // + // 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)) + ); + + // Property wrapper with get & set accessors. + public Uri AquariumGraphic + { + get => (Uri)GetValue(AquariumGraphicProperty); + set => SetValue(AquariumGraphicProperty, value); + } + + // Property-changed callback. + private static void OnUriChanged(DependencyObject dependencyObject, + DependencyPropertyChangedEventArgs e) + { + // Some custom logic that runs on effective property value change. + Uri newValue = (Uri)dependencyObject.GetValue(AquariumGraphicProperty); + Debug.WriteLine($"OnUriChanged: {newValue}"); + } + // + } +} diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/csharp/Properties/Resources.Designer.cs b/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/csharp/Properties/Resources.Designer.cs new file mode 100644 index 0000000000..64552f96fd --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/csharp/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// 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. +// +//------------------------------------------------------------------------------ + +namespace CodeSampleCsharp.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // 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() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [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; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/csharp/Properties/Resources.resx b/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/csharp/Properties/Resources.resx new file mode 100644 index 0000000000..1af7de150c --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/csharp/Properties/Resources.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/csharp/app.xaml b/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/csharp/app.xaml new file mode 100644 index 0000000000..867d2f015f --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/csharp/app.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/vb/Application.xaml b/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/vb/Application.xaml new file mode 100644 index 0000000000..f225972592 --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/vb/Application.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/vb/Application.xaml.vb b/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/vb/Application.xaml.vb new file mode 100644 index 0000000000..084cbe917e --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/vb/Application.xaml.vb @@ -0,0 +1,6 @@ +Class Application + + ' Application-level events, such as Startup, Exit, and DispatcherUnhandledException + ' can be handled in this file. + +End Class diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/vb/AssemblyInfo.vb b/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/vb/AssemblyInfo.vb new file mode 100644 index 0000000000..025ee7271e --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/vb/AssemblyInfo.vb @@ -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) + diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/vb/CodeSampleVb.vbproj b/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/vb/CodeSampleVb.vbproj new file mode 100644 index 0000000000..34db9b0460 --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/vb/CodeSampleVb.vbproj @@ -0,0 +1,22 @@ + + + + WinExe + net6.0-windows + CodeSampleVb + true + + + + + + + + + + + + + + + diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/vb/MainWindow.xaml b/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/vb/MainWindow.xaml new file mode 100644 index 0000000000..37a7457b77 --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/vb/MainWindow.xaml @@ -0,0 +1,5 @@ + + diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/vb/MainWindow.xaml.vb b/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/vb/MainWindow.xaml.vb new file mode 100644 index 0000000000..c508a8a430 --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/xaml-loading-and-dependency-properties/vb/MainWindow.xaml.vb @@ -0,0 +1,62 @@ +Namespace CodeSampleVb + + ' + ' Interaction logic for MainWindow.xaml. + ' + Partial Public Class MainWindow + Inherits Window + + Public Sub New() + InitializeComponent() + + ' Test code. + Dim aquarium As New Aquarium With { + .AquariumGraphic = New Uri("http://www.contoso.com/aquarium-graphic-new.jpg") + } + Debug.WriteLine($"Aquarium graphic: {aquarium.AquariumGraphic}") + End Sub + + ' Output: + ' OnUriChanged http://www.contoso.com/aquarium-graphic-new.jpg + ' Aquarium graphic: http://www.contoso.com/aquarium-graphic-new.jpg + End Class + + Public Class Aquarium + Inherits DependencyObject + + ' + ' 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))) + + ' Property 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 + + ' Property-changed callback. + Private Shared Sub OnUriChanged(dependencyObject As DependencyObject, + e As DependencyPropertyChangedEventArgs) + ' Some custom logic that runs on effective property value change. + Dim newValue As Uri = CType(dependencyObject.GetValue(AquariumGraphicProperty), Uri) + Debug.WriteLine($"OnUriChanged: {newValue}") + End Sub + ' + + End Class + +End Namespace diff --git a/dotnet-desktop-guide/net/wpf/properties/xaml-loading-and-dependency-properties.md b/dotnet-desktop-guide/net/wpf/properties/xaml-loading-and-dependency-properties.md new file mode 100644 index 0000000000..e6ab66544e --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/xaml-loading-and-dependency-properties.md @@ -0,0 +1,56 @@ +--- +title: "XAML loading and dependency properties" +description: "Learn about Extensible Application Markup Language (XAML) loading of dependency property in Windows Presentation Foundation (WPF)." +ms.date: "12/22/2021" +dev_langs: + - "csharp" + - "vb" +helpviewer_keywords: + - "custom dependency properties [WPF]" + - "dependency properties [WPF], XAML loading" + - "loading XML data [WPF]" +--- + + +# XAML loading and dependency properties (WPF .NET) + +The Windows Presentation Foundation (WPF) implementation of its Extensible Application Markup Language (XAML) processor is inherently dependency property aware. As such, the XAML processor uses WPF property system methods to load XAML and process dependency property attributes, and entirely bypasses dependency property wrappers by using WPF property system methods like and . So, if you add custom logic to the property wrapper of your custom dependency property, it won't be called by the XAML processor when a property value is set in XAML. + +[!INCLUDE [desktop guide under construction](../../includes/desktop-guide-preview-note.md)] + +## 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. + +## WPF XAML loader performance + +It's computationally less expensive for the WPF XAML processor to directly call to set the value of a dependency property, rather than use the property wrapper of a dependency property. + +If the XAML processor did use the property wrapper, it would require inferring the entire object model of the backing code based only on the type and member relationships indicated in markup. Although the type can be identified from markup by using a combination of `xmlns` and assembly attributes, identifying the members, determining which members can be set as an attribute, and resolving supported property value types, would require extensive reflection using . + +The WPF property system maintains a storage table of dependency properties implemented on a given derived type. The XAML processor uses that table to infer the dependency property identifier for a dependency property. For example, by convention the dependency property identifier for a dependency property named `ABC` is `ABCProperty`. The XAML processor can efficiently set the value of any dependency property by calling the `SetValue` method on its containing type using the dependency property identifier. + +For more information on dependency property wrappers, see [Custom dependency properties](custom-dependency-properties.md). + +## Implications for custom dependency properties + +The WPF XAML processor bypasses property wrappers and directly calls to set a dependency property value. So, avoid putting any extra logic in the `set` accessor of your custom dependency property because that logic won't run when a property value is set in XAML. The `set` accessor should only contain a `SetValue` call. + +Similarly, aspects of the WPF XAML processor that get property values bypass the property wrapper and directly call . So, also avoid putting any extra logic in the `get` accessor of your custom dependency property because that logic won't run when a property value is read in XAML. The `get` accessor should only contain a `GetValue` call. + +## Dependency property with wrapper example + +The following example shows a recommended dependency property definition with property wrappers. The dependency property identifier is stored as a `public static readonly` field, and the `get` and `set` accessors contain no code beyond the necessary WPF property system methods that back the dependency property value. If you have code that needs to run when the value of your dependency property changes, consider putting that code in the for your dependency property. For more information, see [Property-changed callbacks](/dotnet/desktop/wpf/properties/dependency-property-callbacks-and-validation?preserve-view=true#property-changed-callbacks). + +:::code language="csharp" source="./snippets/xaml-loading-and-dependency-properties/csharp/MainWindow.xaml.cs" id="DependencyPropertyWithWrapper"::: +:::code language="vb" source="./snippets/xaml-loading-and-dependency-properties/vb/MainWindow.xaml.vb" id="DependencyPropertyWithWrapper"::: + +## See also + +- [Dependency properties overview](dependency-properties-overview.md) +- [XAML in WPF](/dotnet/desktop/wpf/advanced/xaml-in-wpf?view=netframeworkdesktop-4.8&preserve-view=true) +- [Custom dependency properties](custom-dependency-properties.md) +- [Dependency property metadata](dependency-property-metadata.md) +- [Collection-type dependency properties](collection-type-dependency-properties.md) +- [Dependency property security](dependency-property-security.md) +- [Safe constructor patterns for DependencyObjects](/dotnet/desktop/wpf/advanced/safe-constructor-patterns-for-dependencyobjects?view=netframeworkdesktop-4.8&preserve-view=true) diff --git a/dotnet-desktop-guide/net/wpf/toc.yml b/dotnet-desktop-guide/net/wpf/toc.yml index e697dea2cc..411c7084b8 100644 --- a/dotnet-desktop-guide/net/wpf/toc.yml +++ b/dotnet-desktop-guide/net/wpf/toc.yml @@ -102,6 +102,8 @@ items: href: properties/dependency-property-security.md - name: Safe constructor patterns for DependencyObjects href: properties/safe-constructor-patterns-for-dependencyobjects.md + - name: XAML loading and dependency properties + href: properties/xaml-loading-and-dependency-properties.md - name: Common tasks items: - name: Implement a dependency property diff --git a/redirects_generator/definitions.json b/redirects_generator/definitions.json index d3f02b2625..4172523fdb 100644 --- a/redirects_generator/definitions.json +++ b/redirects_generator/definitions.json @@ -395,6 +395,10 @@ "SourceUrl": "/dotnet/desktop/wpf/advanced/safe-constructor-patterns-for-dependencyobjects?view=netframeworkdesktop-4.8", "TargetUrl": "/dotnet/desktop/wpf/properties/safe-constructor-patterns-for-dependencyobjects?view=netdesktop-6.0" }, + { + "SourceUrl": "/dotnet/desktop/wpf/advanced/xaml-loading-and-dependency-properties?view=netframeworkdesktop-4.8", + "TargetUrl": "/dotnet/desktop/wpf/properties/xaml-loading-and-dependency-properties?view=netdesktop-6.0" + }, // Systems - XAML { From e990fbc9a643f8d7b4347e254d4a25c0698a9db5 Mon Sep 17 00:00:00 2001 From: Tris Shores <86677757+v-trisshores@users.noreply.github.com> Date: Wed, 5 Jan 2022 17:16:55 -0600 Subject: [PATCH 3/3] Content update - Property value inheritance (user story 1878471) (#1261) * Add article, code, toc, and redirects * Resolve vb project issues * Update .openpublishing.redirection.json Co-authored-by: Andy (Steve) De George <67293991+adegeo@users.noreply.github.com> --- .openpublishing.redirection.json | 8 + .../properties/property-value-inheritance.md | 75 ++++++ .../csharp/App.xaml.cs | 17 ++ .../csharp/AssemblyInfo.cs | 10 + .../csharp/CodeSampleCsharp.csproj | 10 + .../csharp/MainWindow.xaml | 29 ++ .../csharp/MainWindow.xaml.cs | 253 ++++++++++++++++++ .../csharp/Properties/Resources.Designer.cs | 63 +++++ .../csharp/Properties/Resources.resx | 120 +++++++++ .../csharp/app.xaml | 9 + .../vb/Application.xaml | 8 + .../vb/Application.xaml.vb | 6 + .../vb/AssemblyInfo.vb | 9 + .../vb/CodeSampleVb.vbproj | 23 ++ .../vb/MainWindow.xaml | 29 ++ .../vb/MainWindow.xaml.vb | 253 ++++++++++++++++++ dotnet-desktop-guide/net/wpf/toc.yml | 2 + redirects_generator/definitions.json | 4 + 18 files changed, 928 insertions(+) create mode 100644 dotnet-desktop-guide/net/wpf/properties/property-value-inheritance.md create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/csharp/App.xaml.cs create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/csharp/AssemblyInfo.cs create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/csharp/CodeSampleCsharp.csproj create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/csharp/MainWindow.xaml create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/csharp/MainWindow.xaml.cs create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/csharp/Properties/Resources.Designer.cs create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/csharp/Properties/Resources.resx create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/csharp/app.xaml create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/vb/Application.xaml create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/vb/Application.xaml.vb create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/vb/AssemblyInfo.vb create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/vb/CodeSampleVb.vbproj create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/vb/MainWindow.xaml create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/vb/MainWindow.xaml.vb diff --git a/.openpublishing.redirection.json b/.openpublishing.redirection.json index 958fc6daf3..2ea2fcc661 100644 --- a/.openpublishing.redirection.json +++ b/.openpublishing.redirection.json @@ -589,6 +589,14 @@ "source_path": "dotnet-desktop-guide/framework/wpf/properties/safe-constructor-patterns-for-dependencyobjects.md", "redirect_url": "/dotnet/desktop/wpf/advanced/safe-constructor-patterns-for-dependencyobjects?view=netframeworkdesktop-4.8" }, + { + "source_path": "dotnet-desktop-guide/net/wpf/advanced/property-value-inheritance.md", + "redirect_url": "/dotnet/desktop/wpf/properties/property-value-inheritance?view=netdesktop-6.0" + }, + { + "source_path": "dotnet-desktop-guide/framework/wpf/properties/property-value-inheritance.md", + "redirect_url": "/dotnet/desktop/wpf/advanced/property-value-inheritance?view=netframeworkdesktop-4.8" + }, { "source_path": "dotnet-desktop-guide/net/wpf/advanced/xaml-loading-and-dependency-properties.md", "redirect_url": "/dotnet/desktop/wpf/properties/xaml-loading-and-dependency-properties?view=netdesktop-6.0" diff --git a/dotnet-desktop-guide/net/wpf/properties/property-value-inheritance.md b/dotnet-desktop-guide/net/wpf/properties/property-value-inheritance.md new file mode 100644 index 0000000000..a7fd99d52f --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/property-value-inheritance.md @@ -0,0 +1,75 @@ +--- +title: "Dependency property value inheritance" +description: "Learn how dependency property value inheritance can be used to propagate property values in Windows Presentation Foundation (WPF)." +ms.date: "12/29/2021" +dev_langs: + - "csharp" + - "vb" +helpviewer_keywords: + - "inheritance [WPF], property values" + - "value inheritance [WPF]" + - "properties [WPF], value inheritance" +--- + + +# Property value inheritance (WPF .NET) + +Property value inheritance is a feature of the Windows Presentation Foundation (WPF) property system and applies to dependency properties. Property value inheritance lets child elements in a tree of elements obtain the value of a particular property from the nearest parent element. Since a parent element might also have obtained its property value through property value inheritance, the system potentially recurses back to the page root. + +The WPF property system doesn't enable property value inheritance by default, and value inheritance is inactive unless specifically enabled in dependency property [metadata](). Even with property value inheritance enabled, a child element will only inherit a property value in the absence of a higher [precedence](/dotnet/desktop/wpf/properties/dependency-property-value-precedence#dependency-property-setting-precedence-list) value. + +[!INCLUDE [desktop guide under construction](../../includes/desktop-guide-preview-note.md)] + +## 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. + +## Inheritance through an element tree + +Property value inheritance isn't the same concept as class inheritance in object-oriented programming, where derived classes inherit base class members. That kind of inheritance is also active in WPF, although in XAML the inherited base class properties are exposed as attributes of XAML elements that represent derived classes. + +Property value inheritance is the mechanism by which a dependency property value propagates from parent to child elements within a tree of elements that contain the property. In XAML markup, a tree of elements is visible as nested elements. + +The following example shows nested elements in XAML. WPF registers the dependency property on the class with property [metadata](framework-property-metadata.md) that enables property value [inheritance]() and sets the default value to `false`. The `AllowDrop` dependency property exists on , , and elements since they all derive from `UIElement`. Since the `AllowDrop` dependency property on `canvas1` is set to `true`, the descendant `stackPanel1` and `label1` elements inherit `true` as their `AllowDrop` value. + +:::code language="xaml" source="./snippets/property-value-inheritance/csharp/MainWindow.xaml" id="XamlElementTree"::: + +You can also create a tree of elements programmatically by adding element objects to the child element collection of another element object. At run time, property value inheritance operates on the resultant object tree. In the following example, `stackPanel2` is added to the [child collection]() of `canvas2`. Similarly, `label2` is added to the child collection of `stackPanel2`. Since the dependency property on `canvas2` is set to `true`, the descendant `stackPanel2` and `label2` elements inherit `true` as their `AllowDrop` value. + +:::code language="csharp" source="./snippets/property-value-inheritance/csharp/MainWindow.xaml.cs" id="CodeElementTree"::: +:::code language="vb" source="./snippets/property-value-inheritance/vb/MainWindow.xaml.vb" id="CodeElementTree"::: + +## Practical applications of property value inheritance + +Specific WPF dependency properties have value inheritance enabled by default, such as and . Typically, properties with value inheritance enabled by default are implemented on base UI element classes, so they exist on derived classes. For example, since `AllowDrop` is implemented on the base class, that dependency property also exists on every control derived from `UIElement`. WPF enables value inheritance on dependency properties for which it's convenient for a user to set the property value once on a parent element and have that property value propagate to descendant elements in the element tree. + +The property value inheritance model assigns property values, both inherited and uninherited, according to [dependency property value precedence](/dotnet/desktop/wpf/properties/dependency-property-value-precedence#dependency-property-setting-precedence-list). So, a parent element property value will only get applied to a child element, if the child element property doesn't have a higher precedence value, such as a locally set value, or a value obtained through styles, templates, or data binding. + +The dependency property sets the layout direction of text and child UI elements within a parent element. Typically, you would expect the flow direction of text and UI elements within a page to be consistent. Since value inheritance is enabled in the property [metadata]() of `FlowDirection`, a value need only be set once at the top of the element tree for a page. In the rare case where a mix of flow directions is intended for a page, a different flow direction can be set on an element in the tree by assigning a locally set value. The new flow direction will then propagate to descendant elements below that level. + +## Making a custom property inheritable + +You can make a custom dependency property inheritable by enabling the property in an instance of , and then registering your custom dependency property with that metadata instance. By default, `Inherits` is set to `false` in `FrameworkPropertyMetadata`. Making a property value inheritable affects performance, so only set `Inherits` to `true` if that feature is needed. + +When you register a dependency property with `Inherits` enabled in metadata, use the method as described in [Register an attached property](how-to-register-an-attached-property.md). Also, assign a default value to the property so that an inheritable value exists. You might also want to create a property wrapper with `get` and `set` accessors on the owner type, just as you would for a nonattached dependency property. That way you can set the property value using the property wrapper on an owner or derived type. The following example creates a dependency property named `IsTransparent`, with `Inherits` enabled and a default value of `false`. The example also includes a property wrapper with `get` and `set` accessors. + +:::code language="csharp" source="./snippets/property-value-inheritance/csharp/MainWindow.xaml.cs" id="RegisterAttachedPropertyWithValueInheritance"::: +:::code language="vb" source="./snippets/property-value-inheritance/vb/MainWindow.xaml.vb" id="RegisterAttachedPropertyWithValueInheritance"::: + +Attached properties are conceptually similar to global properties. You can check their value on any and get a valid result. The typical scenario for attached properties is to set property values on child elements, and that scenario is more effective if the property in question is implicitly present as an attached property on each element in the tree. + +## Inheriting property values across tree boundaries + +Property inheritance works by traversing a tree of elements. This tree is often parallel to the logical tree. However, whenever you include a WPF core-level object, such as a , in the markup that defines an element tree, you've created a discontinuous logical tree. A true logical tree doesn't conceptually extend through the `Brush`, because the logical tree is a WPF framework-level concept. You can use the helper methods of to analyze and view the extent of a logical tree. Property value inheritance is able to pass inherited values through a discontinuous logical tree, but only if the inheritable property was registered as an attached property and there isn't a deliberate inheritance-blocking boundary, such as a . + +> [!NOTE] +> Although property value inheritance might appear to work for nonattached dependency properties, the inheritance behavior for a nonattached property through some element boundaries in the runtime tree is undefined. Whenever you specify in property metadata, register your properties using . + +## See also + +- [Dependency property metadata](dependency-property-metadata.md) +- [Attached properties overview](attached-properties-overview.md) +- [Register an attached property](how-to-register-an-attached-property.md) +- [Custom dependency properties](custom-dependency-properties.md) +- [Dependency property value precedence](dependency-property-value-precedence.md) +- [Framework property metadata](framework-property-metadata.md) diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/csharp/App.xaml.cs b/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/csharp/App.xaml.cs new file mode 100644 index 0000000000..31285520b3 --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/csharp/App.xaml.cs @@ -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 +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/csharp/AssemblyInfo.cs b/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/csharp/AssemblyInfo.cs new file mode 100644 index 0000000000..8b5504ecfb --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/csharp/AssemblyInfo.cs @@ -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) +)] diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/csharp/CodeSampleCsharp.csproj b/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/csharp/CodeSampleCsharp.csproj new file mode 100644 index 0000000000..2a8c8c1918 --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/csharp/CodeSampleCsharp.csproj @@ -0,0 +1,10 @@ + + + + WinExe + net6.0-windows + true + en-US + + + diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/csharp/MainWindow.xaml b/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/csharp/MainWindow.xaml new file mode 100644 index 0000000000..45e63b4979 --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/csharp/MainWindow.xaml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/csharp/MainWindow.xaml.cs b/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/csharp/MainWindow.xaml.cs new file mode 100644 index 0000000000..feed7b5081 --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/csharp/MainWindow.xaml.cs @@ -0,0 +1,253 @@ +using System.Diagnostics; +using System.Windows; +using System.Windows.Controls; + +namespace CodeSampleCsharp +{ + /// + /// Interaction logic for MainWindow.xaml. + /// + public partial class MainWindow : Window + { + public MainWindow() + { + InitializeComponent(); + + // Code tests. + TestAllowDropInheritanceInXaml(); + TestAllowDropInheritanceInCode(); + TestIsTransparentInheritanceInCode(); + TestDependencyPropertyWrapper(); + } + + private void TestAllowDropInheritanceInXaml() + { + // Test enabled property value inheritance. + FrameworkPropertyMetadata fpm1 = (FrameworkPropertyMetadata) + AllowDropProperty.GetMetadata(typeof(Canvas)); + Debug.Assert(fpm1.Inherits == true); + Debug.Assert(canvas1.AllowDrop == true); + Debug.Assert(stackPanel1.AllowDrop == true); + Debug.Assert(label1.AllowDrop == true); + + // Test disabled property value inheritance. + FrameworkPropertyMetadata fpm11 = (FrameworkPropertyMetadata) + AllowDropProperty.GetMetadata(typeof(Canvas_AllowDropInheritDisabled)); + Debug.Assert(fpm11.Inherits == false); + Debug.Assert(canvas11.AllowDrop == true); + Debug.Assert(stackPanel11.AllowDrop == false); + Debug.Assert(label11.AllowDrop == false); + } + + private static void TestAllowDropInheritanceInCode() + { + // + Canvas canvas2 = new() + { + AllowDrop = true + }; + StackPanel stackPanel2 = new(); + Label label2 = new(); + canvas2.Children.Add(stackPanel2); + stackPanel2.Children.Add(label2); + // + + // Test enabled property value inheritance. + FrameworkPropertyMetadata fpm2 = (FrameworkPropertyMetadata) + AllowDropProperty.GetMetadata(typeof(Canvas)); + Debug.Assert(fpm2.Inherits == true); + Debug.Assert(canvas2.AllowDrop == true); + Debug.Assert(stackPanel2.AllowDrop == true); + Debug.Assert(label2.AllowDrop == true); + + // Test disabled property value inheritance. + Canvas_AllowDropInheritDisabled canvas3 = new() + { + AllowDrop = true + }; + StackPanel stackPanel3 = new(); + Label label3 = new(); + canvas3.Children.Add(stackPanel3); + stackPanel3.Children.Add(label3); + FrameworkPropertyMetadata fpm3 = (FrameworkPropertyMetadata) + AllowDropProperty.GetMetadata(typeof(Canvas_AllowDropInheritDisabled)); + Debug.Assert(fpm3.Inherits == false); + Debug.Assert(canvas3.AllowDrop == true); + Debug.Assert(stackPanel3.AllowDrop == false); + Debug.Assert(label3.AllowDrop == false); + } + + private static void TestIsTransparentInheritanceInCode() + { + // Test enabled property value inheritance. + Canvas_IsTransparentInheritEnabled myCanvas1 = new() + { + IsTransparent = true + }; + Canvas_IsTransparentInheritEnabled2 myCanvas2 = new(); + Canvas_IsTransparentInheritEnabled3 myCanvas3 = new(); + myCanvas1.Children.Add(myCanvas2); + myCanvas2.Children.Add(myCanvas3); + FrameworkPropertyMetadata fpm1 = (FrameworkPropertyMetadata)Canvas_IsTransparentInheritEnabled + .IsTransparentProperty.GetMetadata(typeof(Canvas_IsTransparentInheritEnabled)); + Debug.Assert(fpm1.Inherits == true); + Debug.Assert(myCanvas1.IsTransparent == true); + Debug.Assert(myCanvas2.IsTransparent == true); + Debug.Assert(myCanvas3.IsTransparent == true); + + // Test disabled property value inheritance. + Canvas_IsTransparentInheritDisabled myCanvas4 = new() + { + IsTransparent = true + }; + Canvas_IsTransparentInheritDisabled2 myCanvas5 = new(); + Canvas_IsTransparentInheritDisabled3 myCanvas6 = new(); + myCanvas4.Children.Add(myCanvas5); + myCanvas5.Children.Add(myCanvas6); + FrameworkPropertyMetadata fpm2 = (FrameworkPropertyMetadata)Canvas_IsTransparentInheritDisabled + .IsTransparentProperty.GetMetadata(typeof(Canvas_IsTransparentInheritDisabled)); + Debug.Assert(fpm2.Inherits == false); + Debug.Assert(myCanvas4.IsTransparent == true); + Debug.Assert(myCanvas5.IsTransparent == false); + Debug.Assert(myCanvas6.IsTransparent == false); + } + + private static void TestDependencyPropertyWrapper() + { + // Test Canvas_IsTransparentInheritEnabled. + Canvas_IsTransparentInheritEnabled myCanvas1 = new(); + Canvas_IsTransparentInheritEnabled2 myCanvas2 = new(); + Canvas_IsTransparentInheritEnabled3 myCanvas3 = new(); + // Test property wrapper. + myCanvas1.IsTransparent = true; + myCanvas2.IsTransparent = false; + myCanvas3.IsTransparent = true; + Debug.Assert(myCanvas1.IsTransparent == true); + Debug.Assert(myCanvas2.IsTransparent == false); + Debug.Assert(myCanvas3.IsTransparent == true); + // Test individual get/set accessors. + Canvas_IsTransparentInheritEnabled.SetIsTransparent(myCanvas1, false); + Canvas_IsTransparentInheritEnabled.SetIsTransparent(myCanvas2, true); + Canvas_IsTransparentInheritEnabled.SetIsTransparent(myCanvas3, false); + Debug.Assert(Canvas_IsTransparentInheritEnabled.GetIsTransparent(myCanvas1) == false); + Debug.Assert(Canvas_IsTransparentInheritEnabled.GetIsTransparent(myCanvas2) == true); + Debug.Assert(Canvas_IsTransparentInheritEnabled.GetIsTransparent(myCanvas3) == false); + + // Test Canvas_IsTransparentInheritDisabled. + Canvas_IsTransparentInheritDisabled myCanvas4 = new(); + Canvas_IsTransparentInheritDisabled2 myCanvas5 = new(); + Canvas_IsTransparentInheritDisabled3 myCanvas6 = new(); + // Test property wrapper. + myCanvas4.IsTransparent = true; + myCanvas5.IsTransparent = false; + myCanvas6.IsTransparent = true; + Debug.Assert(myCanvas4.IsTransparent == true); + Debug.Assert(myCanvas5.IsTransparent == false); + Debug.Assert(myCanvas6.IsTransparent == true); + // Test individual get/set accessors. + Canvas_IsTransparentInheritDisabled.SetIsTransparent(myCanvas4, false); + Canvas_IsTransparentInheritDisabled.SetIsTransparent(myCanvas5, true); + Canvas_IsTransparentInheritDisabled.SetIsTransparent(myCanvas6, false); + Debug.Assert(Canvas_IsTransparentInheritDisabled.GetIsTransparent(myCanvas4) == false); + Debug.Assert(Canvas_IsTransparentInheritDisabled.GetIsTransparent(myCanvas5) == true); + Debug.Assert(Canvas_IsTransparentInheritDisabled.GetIsTransparent(myCanvas6) == false); + } + } + + public class Canvas_AllowDropInheritDisabled : Canvas + { + static Canvas_AllowDropInheritDisabled() + { + // Disable property value inheritance in a new property metadata object. + FrameworkPropertyMetadata frameworkPropertyMetadata = new(); + frameworkPropertyMetadata.Inherits = false; + // Override existing property metadata. + AllowDropProperty.OverrideMetadata(typeof(Canvas_AllowDropInheritDisabled), frameworkPropertyMetadata); + } + } + + // + public class Canvas_IsTransparentInheritEnabled : Canvas + { + // Register an attached dependency property with the specified + // property name, property type, owner type, and property metadata + // (default value is 'false' and property value inheritance is enabled). + public static readonly DependencyProperty IsTransparentProperty = + DependencyProperty.RegisterAttached( + name: "IsTransparent", + propertyType: typeof(bool), + ownerType: typeof(Canvas_IsTransparentInheritEnabled), + defaultMetadata: new FrameworkPropertyMetadata( + defaultValue: false, + flags: FrameworkPropertyMetadataOptions.Inherits)); + + // Declare a get accessor method. + public static bool GetIsTransparent(Canvas element) + { + return (bool)element.GetValue(IsTransparentProperty); + } + + // Declare a set accessor method. + public static void SetIsTransparent(Canvas element, bool value) + { + element.SetValue(IsTransparentProperty, value); + } + + // For convenience, declare a property wrapper with get/set accessors. + public bool IsTransparent + { + get => (bool)GetValue(IsTransparentProperty); + set => SetValue(IsTransparentProperty, value); + } + } + // + + public class Canvas_IsTransparentInheritEnabled2 : Canvas_IsTransparentInheritEnabled + { + } + + public class Canvas_IsTransparentInheritEnabled3 : Canvas_IsTransparentInheritEnabled + { + } + + public class Canvas_IsTransparentInheritDisabled : Canvas + { + // Register an attached dependency property with the specified + // property name, property type, owner type, and property metadata + // (default value is 'false' and value inheritance is disabled). + public static readonly DependencyProperty IsTransparentProperty = + DependencyProperty.RegisterAttached( + name: "IsTransparent", + propertyType: typeof(bool), + ownerType: typeof(Canvas_IsTransparentInheritDisabled), + defaultMetadata: new FrameworkPropertyMetadata( + defaultValue: false)); + + // Declare a get accessor method. + public static bool GetIsTransparent(Canvas element) + { + return (bool)element.GetValue(IsTransparentProperty); + } + + // Declare a set accessor method. + public static void SetIsTransparent(Canvas element, bool value) + { + element.SetValue(IsTransparentProperty, value); + } + + // For convenience, declare a property wrapper with get/set accessors. + public bool IsTransparent + { + get => (bool)GetValue(IsTransparentProperty); + set => SetValue(IsTransparentProperty, value); + } + } + + public class Canvas_IsTransparentInheritDisabled2 : Canvas_IsTransparentInheritDisabled + { + } + + public class Canvas_IsTransparentInheritDisabled3 : Canvas_IsTransparentInheritDisabled + { + } +} diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/csharp/Properties/Resources.Designer.cs b/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/csharp/Properties/Resources.Designer.cs new file mode 100644 index 0000000000..64552f96fd --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/csharp/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// 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. +// +//------------------------------------------------------------------------------ + +namespace CodeSampleCsharp.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // 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() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [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; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/csharp/Properties/Resources.resx b/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/csharp/Properties/Resources.resx new file mode 100644 index 0000000000..1af7de150c --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/csharp/Properties/Resources.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/csharp/app.xaml b/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/csharp/app.xaml new file mode 100644 index 0000000000..867d2f015f --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/csharp/app.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/vb/Application.xaml b/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/vb/Application.xaml new file mode 100644 index 0000000000..db8a8eea71 --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/vb/Application.xaml @@ -0,0 +1,8 @@ + + + + + diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/vb/Application.xaml.vb b/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/vb/Application.xaml.vb new file mode 100644 index 0000000000..084cbe917e --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/vb/Application.xaml.vb @@ -0,0 +1,6 @@ +Class Application + + ' Application-level events, such as Startup, Exit, and DispatcherUnhandledException + ' can be handled in this file. + +End Class diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/vb/AssemblyInfo.vb b/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/vb/AssemblyInfo.vb new file mode 100644 index 0000000000..07b608bb2d --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/vb/AssemblyInfo.vb @@ -0,0 +1,9 @@ +'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) + diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/vb/CodeSampleVb.vbproj b/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/vb/CodeSampleVb.vbproj new file mode 100644 index 0000000000..a3f8743bb7 --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/vb/CodeSampleVb.vbproj @@ -0,0 +1,23 @@ + + + + WinExe + net6.0-windows + true + CodeSampleVb + en-US + + + + + + + + + + + + + + + diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/vb/MainWindow.xaml b/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/vb/MainWindow.xaml new file mode 100644 index 0000000000..596ed9c1c1 --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/vb/MainWindow.xaml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/vb/MainWindow.xaml.vb b/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/vb/MainWindow.xaml.vb new file mode 100644 index 0000000000..9fb3d402d9 --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/property-value-inheritance/vb/MainWindow.xaml.vb @@ -0,0 +1,253 @@ +Namespace CodeSampleVb + Partial Public Class MainWindow + Inherits Window + + Public Sub New() + InitializeComponent() + + ' Code tests. + TestAllowDropInheritanceInXaml() + TestAllowDropInheritanceInCode() + TestIsTransparentInheritanceInCode() + TestDependencyPropertyWrapper() + End Sub + + Private Sub TestAllowDropInheritanceInXaml() + + ' Test enabled property value inheritance. + Dim fpm1 As FrameworkPropertyMetadata = + CType(AllowDropProperty. + GetMetadata(GetType(Canvas)), FrameworkPropertyMetadata) + Debug.Assert(fpm1.[Inherits] = True) + Debug.Assert(canvas1.AllowDrop = True) + Debug.Assert(stackPanel1.AllowDrop = True) + Debug.Assert(label1.AllowDrop = True) + + ' Test disabled property value inheritance. + Dim fpm11 As FrameworkPropertyMetadata = + CType(AllowDropProperty. + GetMetadata(GetType(Canvas_AllowDropInheritDisabled)), FrameworkPropertyMetadata) + Debug.Assert(fpm11.[Inherits] = False) + ' Debug.Assert(canvas11.AllowDrop = True) + Debug.Assert(stackPanel11.AllowDrop = False) + Debug.Assert(label11.AllowDrop = False) + End Sub + + Private Shared Sub TestAllowDropInheritanceInCode() + + ' + Dim canvas2 As New Canvas With { + .AllowDrop = True + } + Dim stackPanel2 As New StackPanel() + Dim label2 As New Label() + canvas2.Children.Add(stackPanel2) + stackPanel2.Children.Add(label2) + ' + + ' Test enabled property value inheritance. + Dim fpm2 As FrameworkPropertyMetadata = + CType(AllowDropProperty. + GetMetadata(GetType(Canvas)), FrameworkPropertyMetadata) + Debug.Assert(fpm2.[Inherits] = True) + Debug.Assert(canvas2.AllowDrop = True) + Debug.Assert(stackPanel2.AllowDrop = True) + Debug.Assert(label2.AllowDrop = True) + + ' Test disabled property value inheritance. + Dim canvas3 As New Canvas_AllowDropInheritDisabled With { + .AllowDrop = True + } + Dim stackPanel3 As New StackPanel() + Dim label3 As New Label() + canvas3.Children.Add(stackPanel3) + stackPanel3.Children.Add(label3) + Dim fpm3 As FrameworkPropertyMetadata = + CType(AllowDropProperty. + GetMetadata(GetType(Canvas_AllowDropInheritDisabled)), FrameworkPropertyMetadata) + Debug.Assert(fpm3.[Inherits] = False) + Debug.Assert(canvas3.AllowDrop = True) + Debug.Assert(stackPanel3.AllowDrop = False) + Debug.Assert(label3.AllowDrop = False) + + End Sub + + Private Shared Sub TestIsTransparentInheritanceInCode() + + ' Test enabled property value inheritance. + Dim myCanvas1 As New Canvas_IsTransparentInheritEnabled With { + .IsTransparent = True + } + Dim myCanvas2 As New Canvas_IsTransparentInheritEnabled2() + Dim myCanvas3 As New Canvas_IsTransparentInheritEnabled3() + myCanvas1.Children.Add(myCanvas2) + myCanvas2.Children.Add(myCanvas3) + Dim fpm1 As FrameworkPropertyMetadata = + CType(Canvas_IsTransparentInheritEnabled.IsTransparentProperty. + GetMetadata(GetType(Canvas_IsTransparentInheritEnabled)), FrameworkPropertyMetadata) + Debug.Assert(fpm1.[Inherits] = True) + Debug.Assert(myCanvas1.IsTransparent = True) + Debug.Assert(myCanvas2.IsTransparent = True) + Debug.Assert(myCanvas3.IsTransparent = True) + + ' Test disabled property value inheritance. + Dim myCanvas4 As New Canvas_IsTransparentInheritDisabled With { + .IsTransparent = True + } + Dim myCanvas5 As New Canvas_IsTransparentInheritDisabled2() + Dim myCanvas6 As New Canvas_IsTransparentInheritDisabled3() + myCanvas4.Children.Add(myCanvas5) + myCanvas5.Children.Add(myCanvas6) + Dim fpm2 As FrameworkPropertyMetadata = + CType(Canvas_IsTransparentInheritDisabled.IsTransparentProperty. + GetMetadata(GetType(Canvas_IsTransparentInheritDisabled)), FrameworkPropertyMetadata) + Debug.Assert(fpm2.[Inherits] = False) + Debug.Assert(myCanvas4.IsTransparent = True) + Debug.Assert(myCanvas5.IsTransparent = False) + Debug.Assert(myCanvas6.IsTransparent = False) + + End Sub + + Private Shared Sub TestDependencyPropertyWrapper() + + ' Test Canvas_IsTransparentInheritEnabled. + Dim myCanvas1 As New Canvas_IsTransparentInheritEnabled() + Dim myCanvas2 As New Canvas_IsTransparentInheritEnabled2() + Dim myCanvas3 As New Canvas_IsTransparentInheritEnabled3() + ' Test property wrapper. + myCanvas1.IsTransparent = True + myCanvas2.IsTransparent = False + myCanvas3.IsTransparent = True + Debug.Assert(myCanvas1.IsTransparent = True) + Debug.Assert(myCanvas2.IsTransparent = False) + Debug.Assert(myCanvas3.IsTransparent = True) + ' Test individual get/set accessors. + Canvas_IsTransparentInheritEnabled.SetIsTransparent(myCanvas1, False) + Canvas_IsTransparentInheritEnabled.SetIsTransparent(myCanvas2, True) + Canvas_IsTransparentInheritEnabled.SetIsTransparent(myCanvas3, False) + Debug.Assert(Canvas_IsTransparentInheritEnabled.GetIsTransparent(myCanvas1) = False) + Debug.Assert(Canvas_IsTransparentInheritEnabled.GetIsTransparent(myCanvas2) = True) + Debug.Assert(Canvas_IsTransparentInheritEnabled.GetIsTransparent(myCanvas3) = False) + + ' Test Canvas_IsTransparentInheritDisabled. + Dim myCanvas4 As New Canvas_IsTransparentInheritDisabled() + Dim myCanvas5 As New Canvas_IsTransparentInheritDisabled2() + Dim myCanvas6 As New Canvas_IsTransparentInheritDisabled3() + ' Test property wrapper. + myCanvas4.IsTransparent = True + myCanvas5.IsTransparent = False + myCanvas6.IsTransparent = True + Debug.Assert(myCanvas4.IsTransparent = True) + Debug.Assert(myCanvas5.IsTransparent = False) + Debug.Assert(myCanvas6.IsTransparent = True) + ' Test individual get/set accessors. + Canvas_IsTransparentInheritDisabled.SetIsTransparent(myCanvas4, False) + Canvas_IsTransparentInheritDisabled.SetIsTransparent(myCanvas5, True) + Canvas_IsTransparentInheritDisabled.SetIsTransparent(myCanvas6, False) + Debug.Assert(Canvas_IsTransparentInheritDisabled.GetIsTransparent(myCanvas4) = False) + Debug.Assert(Canvas_IsTransparentInheritDisabled.GetIsTransparent(myCanvas5) = True) + Debug.Assert(Canvas_IsTransparentInheritDisabled.GetIsTransparent(myCanvas6) = False) + + End Sub + End Class + + Public Class Canvas_AllowDropInheritDisabled + Inherits Canvas + Shared Sub New() + ' Disable property value inheritance in a new property metadata object. + Dim frameworkPropertyMetadata As New FrameworkPropertyMetadata With { + .Inherits = False + } + ' Override existing property metadata. + AllowDropProperty.OverrideMetadata(GetType(Canvas_AllowDropInheritDisabled), frameworkPropertyMetadata) + End Sub + End Class + + ' + Public Class Canvas_IsTransparentInheritEnabled + Inherits Canvas + + ' Register an attached dependency property with the specified + ' property name, property type, owner type, and property metadata + ' (default value is 'false' and property value inheritance is enabled). + Public Shared ReadOnly IsTransparentProperty As DependencyProperty = + DependencyProperty.RegisterAttached( + name:="IsTransparent", + propertyType:=GetType(Boolean), + ownerType:=GetType(Canvas_IsTransparentInheritEnabled), + defaultMetadata:=New FrameworkPropertyMetadata( + defaultValue:=False, + flags:=FrameworkPropertyMetadataOptions.[Inherits])) + + ' Declare a get accessor method. + Public Shared Function GetIsTransparent(element As Canvas) As Boolean + Return element.GetValue(IsTransparentProperty) + End Function + + ' Declare a set accessor method. + Public Shared Sub SetIsTransparent(element As Canvas, value As Boolean) + element.SetValue(IsTransparentProperty, value) + End Sub + + ' For convenience, declare a property wrapper with get/set accessors. + Public Property IsTransparent As Boolean + Get + Return GetValue(IsTransparentProperty) + End Get + Set(value As Boolean) + SetValue(IsTransparentProperty, value) + End Set + End Property + End Class + ' + + Public Class Canvas_IsTransparentInheritEnabled2 + Inherits Canvas_IsTransparentInheritEnabled + End Class + + Public Class Canvas_IsTransparentInheritEnabled3 + Inherits Canvas_IsTransparentInheritEnabled + End Class + + Public Class Canvas_IsTransparentInheritDisabled + Inherits Canvas + + ' Register an attached dependency property with the specified + ' property name, property type, owner type, and property metadata + ' (default value is 'false' and property value inheritance is disabled). + Public Shared ReadOnly IsTransparentProperty As DependencyProperty = + DependencyProperty.RegisterAttached( + name:="IsTransparent", + propertyType:=GetType(Boolean), + ownerType:=GetType(Canvas_IsTransparentInheritDisabled), + defaultMetadata:=New FrameworkPropertyMetadata(defaultValue:=False)) + + ' Declare a get accessor method. + Public Shared Function GetIsTransparent(element As Canvas) As Boolean + Return element.GetValue(IsTransparentProperty) + End Function + + ' Declare a set accessor method. + Public Shared Sub SetIsTransparent(element As Canvas, value As Boolean) + element.SetValue(IsTransparentProperty, value) + End Sub + + ' For convenience, declare a property wrapper with get/set accessors. + Public Property IsTransparent As Boolean + Get + Return GetValue(IsTransparentProperty) + End Get + Set(value As Boolean) + SetValue(IsTransparentProperty, value) + End Set + End Property + End Class + + Public Class Canvas_IsTransparentInheritDisabled2 + Inherits Canvas_IsTransparentInheritDisabled + End Class + + Public Class Canvas_IsTransparentInheritDisabled3 + Inherits Canvas_IsTransparentInheritDisabled + End Class +End Namespace diff --git a/dotnet-desktop-guide/net/wpf/toc.yml b/dotnet-desktop-guide/net/wpf/toc.yml index 411c7084b8..9e6946542f 100644 --- a/dotnet-desktop-guide/net/wpf/toc.yml +++ b/dotnet-desktop-guide/net/wpf/toc.yml @@ -102,6 +102,8 @@ items: href: properties/dependency-property-security.md - name: Safe constructor patterns for DependencyObjects href: properties/safe-constructor-patterns-for-dependencyobjects.md + - name: Property value inheritance + href: properties/property-value-inheritance.md - name: XAML loading and dependency properties href: properties/xaml-loading-and-dependency-properties.md - name: Common tasks diff --git a/redirects_generator/definitions.json b/redirects_generator/definitions.json index 4172523fdb..df0732df01 100644 --- a/redirects_generator/definitions.json +++ b/redirects_generator/definitions.json @@ -395,6 +395,10 @@ "SourceUrl": "/dotnet/desktop/wpf/advanced/safe-constructor-patterns-for-dependencyobjects?view=netframeworkdesktop-4.8", "TargetUrl": "/dotnet/desktop/wpf/properties/safe-constructor-patterns-for-dependencyobjects?view=netdesktop-6.0" }, + { + "SourceUrl": "/dotnet/desktop/wpf/advanced/property-value-inheritance?view=netframeworkdesktop-4.8", + "TargetUrl": "/dotnet/desktop/wpf/properties/property-value-inheritance?view=netdesktop-6.0" + }, { "SourceUrl": "/dotnet/desktop/wpf/advanced/xaml-loading-and-dependency-properties?view=netframeworkdesktop-4.8", "TargetUrl": "/dotnet/desktop/wpf/properties/xaml-loading-and-dependency-properties?view=netdesktop-6.0"