From cf712b82b0eb9b586f79dc76ea81a755bd31296d Mon Sep 17 00:00:00 2001 From: Tris Shores <86677757+v-trisshores@users.noreply.github.com> Date: Fri, 22 Oct 2021 11:55:35 -0500 Subject: [PATCH] Content update - Dependency properties collection (user story 1878471) (#1173) * Add code snippets * Add article and updated code snippets * Resolve conflicts * Make reviewer requested changes * Name class parameters and show how to pass in default value in metedata * Add example for creating a FreezableCollection type dependency property * Add newline * Further edits --- .openpublishing.redirection.json | 8 + .../collection-type-dependency-properties.md | 65 +++++++ .../csharp/App.xaml.cs | 17 ++ .../csharp/AssemblyInfo.cs | 10 ++ .../csharp/CodeSampleCsharp.csproj | 24 +++ .../csharp/MainWindow.xaml | 11 ++ .../csharp/MainWindow.xaml.cs | 141 +++++++++++++++ .../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 | 11 ++ .../vb/MainWindow.xaml.vb | 161 ++++++++++++++++++ dotnet-desktop-guide/net/wpf/toc.yml | 2 + redirects_generator/definitions.json | 5 + 18 files changed, 695 insertions(+) create mode 100644 dotnet-desktop-guide/net/wpf/properties/collection-type-dependency-properties.md create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/csharp/App.xaml.cs create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/csharp/AssemblyInfo.cs create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/csharp/CodeSampleCsharp.csproj create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/csharp/MainWindow.xaml create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/csharp/MainWindow.xaml.cs create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/csharp/Properties/Resources.Designer.cs create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/csharp/Properties/Resources.resx create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/csharp/app.xaml create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/vb/Application.xaml create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/vb/Application.xaml.vb create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/vb/AssemblyInfo.vb create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/vb/CodeSampleVb.vbproj create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/vb/MainWindow.xaml create mode 100644 dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/vb/MainWindow.xaml.vb diff --git a/.openpublishing.redirection.json b/.openpublishing.redirection.json index f71b9a8..6343093 100644 --- a/.openpublishing.redirection.json +++ b/.openpublishing.redirection.json @@ -496,6 +496,14 @@ { "source_path": "dotnet-desktop-guide/framework/wpf/properties/how-to-register-an-attached-property.md", "redirect_url": "/dotnet/desktop/wpf/advanced/how-to-register-an-attached-property?view=netframeworkdesktop-4.8" + }, + { + "source_path": "dotnet-desktop-guide/net/wpf/advanced/collection-type-dependency-properties.md", + "redirect_url": "/dotnet/desktop/wpf/properties/collection-type-dependency-properties?view=netdesktop-5.0" + }, + { + "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" } ] } 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 new file mode 100644 index 0000000..2a0e88f --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/collection-type-dependency-properties.md @@ -0,0 +1,65 @@ +--- +title: "Collection-type dependency properties" +description: "Learn how to implement a dependency property that's a collection type and how to assign a default collection value." +ms.date: "10/06/2021" +dev_langs: + - "csharp" + - "vb" +helpviewer_keywords: + - "properties [WPF], dependency" + - "properties [WPF], collection-type" + - "dependency properties [WPF]" + - "collection-type properties [WPF]" +--- + + +# Collection-type dependency properties (WPF .NET) + +This article provides guidance and suggested patterns for implementing a dependency property that's a collection type. + +## 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. + +## Initialize the collection + +When you create a dependency property, you typically specify the default value through dependency property metadata instead of specifying an initial property value. However, if your property value is a reference type, the default value should be set in the constructor of the class that registers the dependency property. The dependency property metadata shouldn't include a default reference-type value because that value will be assigned to all instances of the class, creating a singleton class. + +The following example declares an `Aquarium` class that contains a collection of elements in a generic . A default collection value isn't included in the passed to the method, and instead the class constructor is used to set the default collection value to a new generic `List`. + +:::code language="csharp" source="./snippets/collection-type-dependency-properties/csharp/MainWindow.xaml.cs" id="SetCollectionDefaultValueInConstructor"::: +:::code language="vb" source="./snippets/collection-type-dependency-properties/vb/MainWindow.xaml.vb" id="SetCollectionDefaultValueInConstructor"::: + +The following test code instantiates two separate `Aquarium` instances and adds a different `Fish` item to each collection. If you run the code, you'll see that each `Aquarium` instance has a single collection item, as expected. + +:::code language="csharp" source="./snippets/collection-type-dependency-properties/csharp/MainWindow.xaml.cs" id="InitializeAquariums"::: +:::code language="vb" source="./snippets/collection-type-dependency-properties/vb/MainWindow.xaml.vb" id="InitializeAquariums"::: + +But, if you comment out the class constructor and pass the default collection value as to the method, you'll see that each `Aquarium` instance gets two collection items! This is because both `Fish` instances are added to the same list, which is shared by all instances of the Aquarium class. So, when the intent is for each object instance to have its own list, the default value should be set in the class constructor. + +### Initialize a read-write collection + +The following example declares a read-write collection-type dependency property in the `Aquarium` class, using the non-key signature methods and . + +:::code language="csharp" source="./snippets/collection-type-dependency-properties/csharp/MainWindow.xaml.cs" id="ReadWriteDependencyProperty"::: +:::code language="vb" source="./snippets/collection-type-dependency-properties/vb/MainWindow.xaml.vb" id="ReadWriteDependencyProperty"::: + +## FreezableCollection dependency properties + +A collection-type dependency property doesn't automatically report changes in its subproperties. As a result, if you're binding to a collection, the binding might not report changes, invalidating some data binding scenarios. But, if you use for the dependency property type, changes to the properties of collection elements are properly reported and binding works as expected. + +To enable subproperty binding in a collection of dependency objects, use the collection type `FreezableCollection`, with a type constraint of any derived class. + +The following example declares an `Aquarium` class that contains a `FreezableCollection` with a type constraint of . A default collection value isn't included in the passed to the method, and instead the class constructor is used to set the default collection value to a new `FreezableCollection`. + +:::code language="csharp" source="./snippets/collection-type-dependency-properties/csharp/MainWindow.xaml.cs" id="FreezableCollectionAquarium"::: +:::code language="vb" source="./snippets/collection-type-dependency-properties/vb/MainWindow.xaml.vb" id="FreezableCollectionAquarium"::: + +## See also + +- +- [XAML and Custom Classes for WPF](/dotnet/desktop/wpf/advanced/xaml-and-custom-classes-for-wpf?view=netframeworkdesktop-4.8&preserve-view=true) +- [Data Binding Overview](/dotnet/desktop/wpf/data/) +- [Dependency Properties Overview](dependency-properties-overview.md) +- [Custom Dependency Properties](/dotnet/desktop/wpf/advanced/custom-dependency-properties?view=netframeworkdesktop-4.8&preserve-view=true) +- [Dependency Property Metadata](/dotnet/desktop/wpf/advanced/dependency-property-metadata?view=netframeworkdesktop-4.8&preserve-view=true) diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/csharp/App.xaml.cs b/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/csharp/App.xaml.cs new file mode 100644 index 0000000..3128552 --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-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/collection-type-dependency-properties/csharp/AssemblyInfo.cs b/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/csharp/AssemblyInfo.cs new file mode 100644 index 0000000..8b5504e --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-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/collection-type-dependency-properties/csharp/CodeSampleCsharp.csproj b/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/csharp/CodeSampleCsharp.csproj new file mode 100644 index 0000000..8824b2f --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/csharp/CodeSampleCsharp.csproj @@ -0,0 +1,24 @@ + + + + WinExe + net5.0-windows + true + + + + + True + True + Resources.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/csharp/MainWindow.xaml b/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/csharp/MainWindow.xaml new file mode 100644 index 0000000..e3a44de --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/csharp/MainWindow.xaml @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/csharp/MainWindow.xaml.cs b/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/csharp/MainWindow.xaml.cs new file mode 100644 index 0000000..4e9c314 --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/csharp/MainWindow.xaml.cs @@ -0,0 +1,141 @@ +using System.Collections.Generic; +using System.Windows; + +namespace CodeSampleCsharp +{ + /// + /// Interaction logic for MainWindow.xaml. + /// + public partial class MainWindow : Window + { + // + private void InitializeAquariums(object sender, RoutedEventArgs e) + { + Aquarium aquarium1 = new(); + Aquarium aquarium2 = new(); + aquarium1.AquariumContents.Add(new Fish()); + aquarium2.AquariumContents.Add(new Fish()); + MessageBox.Show( + $"Aquarium1 contains {aquarium1.AquariumContents.Count} fish\r\n" + + $"Aquarium2 contains {aquarium2.AquariumContents.Count} fish"); + } + // + } + + // + public class Aquarium : DependencyObject + { + // Register a dependency property with the specified property name, + // property type, owner type, and property metadata. + private static readonly DependencyPropertyKey s_aquariumContentsPropertyKey = + DependencyProperty.RegisterReadOnly( + name: "AquariumContents", + propertyType: typeof(List), + ownerType: typeof(Aquarium), + typeMetadata: new FrameworkPropertyMetadata() + //typeMetadata: new FrameworkPropertyMetadata(new List()) + ); + + // Store the dependency property identifier as a static member of the class. + public static readonly DependencyProperty AquariumContentsProperty = + s_aquariumContentsPropertyKey.DependencyProperty; + + // Set the default collection value in a class constructor. + public Aquarium() => SetValue(s_aquariumContentsPropertyKey, new List()); + + // Declare a read-only property. + public List AquariumContents => + (List)GetValue(AquariumContentsProperty); + } + + public class Fish : FrameworkElement { } + // + + public class ReadWriteAquariumContents + { + private static void InitializeAquariums() + { + Aquarium aquarium1 = new(); + Aquarium aquarium2 = new(); + aquarium1.AquariumContents.Add(new Fish()); + aquarium2.AquariumContents.Add(new Fish()); + aquarium2.AquariumContents = new List(); + MessageBox.Show( + $"Aquarium1 contains {aquarium1.AquariumContents.Count} fish\r\n" + + $"Aquarium2 contains {aquarium2.AquariumContents.Count} fish"); + } + + // + public class Aquarium : DependencyObject + { + // Register a dependency property with the specified property name, + // property type, and owner type. + private static readonly DependencyProperty s_aquariumContentsProperty = + DependencyProperty.Register( + name: "AquariumContents", + propertyType: typeof(List), + 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()); + + // Declare a read-write property. + public List AquariumContents + { + get => (List)GetValue(AquariumContentsProperty); + set => SetValue(AquariumContentsProperty, value); + } + } + // + + public class Fish : FrameworkElement { } + } + + public class FreezableCollectionAquarium + { + public static void InitializeAquariums() + { + Aquarium aquarium1 = new(); + Aquarium aquarium2 = new(); + aquarium1.AquariumContents.Add(new Fish()); + aquarium2.AquariumContents.Add(new Fish()); + MessageBox.Show( + $"Aquarium1 contains {aquarium1.AquariumContents.Count} fish\r\n" + + $"Aquarium2 contains {aquarium2.AquariumContents.Count} fish"); + } + + // + public class Aquarium : DependencyObject + { + // Register a dependency property with the specified property name, + // property type, and owner type. + private static readonly DependencyPropertyKey s_aquariumContentsPropertyKey = + DependencyProperty.RegisterReadOnly( + name: "AquariumContents", + propertyType: typeof(FreezableCollection), + ownerType: typeof(Aquarium), + typeMetadata: new FrameworkPropertyMetadata() + ); + + // Store the dependency property identifier as a static member of the class. + public static readonly DependencyProperty AquariumContentsProperty = + s_aquariumContentsPropertyKey.DependencyProperty; + + // Set the default collection value in a class constructor. + public Aquarium() => SetValue(s_aquariumContentsPropertyKey, new FreezableCollection()); + + // Declare a read-only property. + public FreezableCollection AquariumContents => + (FreezableCollection)GetValue(AquariumContentsProperty); + } + + // + + public class Fish : FrameworkElement { } + } +} diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/csharp/Properties/Resources.Designer.cs b/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/csharp/Properties/Resources.Designer.cs new file mode 100644 index 0000000..64552f9 --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-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/collection-type-dependency-properties/csharp/Properties/Resources.resx b/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/csharp/Properties/Resources.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-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/collection-type-dependency-properties/csharp/app.xaml b/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/csharp/app.xaml new file mode 100644 index 0000000..867d2f0 --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/csharp/app.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/vb/Application.xaml b/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/vb/Application.xaml new file mode 100644 index 0000000..f225972 --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/vb/Application.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/vb/Application.xaml.vb b/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/vb/Application.xaml.vb new file mode 100644 index 0000000..084cbe9 --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-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/collection-type-dependency-properties/vb/AssemblyInfo.vb b/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/vb/AssemblyInfo.vb new file mode 100644 index 0000000..025ee72 --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-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/collection-type-dependency-properties/vb/CodeSampleVb.vbproj b/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/vb/CodeSampleVb.vbproj new file mode 100644 index 0000000..c7ae1cc --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/vb/CodeSampleVb.vbproj @@ -0,0 +1,22 @@ + + + + WinExe + net5.0-windows + CodeSampleVb + true + + + + + + + + + + + + + + + diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/vb/MainWindow.xaml b/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/vb/MainWindow.xaml new file mode 100644 index 0000000..2080a2f --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/vb/MainWindow.xaml @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/vb/MainWindow.xaml.vb b/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/vb/MainWindow.xaml.vb new file mode 100644 index 0000000..e031016 --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/properties/snippets/collection-type-dependency-properties/vb/MainWindow.xaml.vb @@ -0,0 +1,161 @@ +Namespace CodeSampleVb + + ' + ' Interaction logic for MainWindow.xaml. + ' + Partial Public Class MainWindow + Inherits Window + + Public Sub New() + InitializeComponent() + End Sub + + ' + Private Sub InitializeAquariums(sender As Object, e As RoutedEventArgs) + Dim aquarium1 As New Aquarium() + Dim aquarium2 As New Aquarium() + aquarium1.AquariumContents.Add(New Fish()) + aquarium2.AquariumContents.Add(New Fish()) + MessageBox.Show($"Aquarium1 contains {aquarium1.AquariumContents.Count} fish{Environment.NewLine}" + + $"Aquarium2 contains {aquarium2.AquariumContents.Count} fish") + End Sub + ' + + End Class + + ' + Public Class Aquarium + Inherits DependencyObject + + ' Register a dependency property with the specified property name, + ' property type, owner type, and property metadata. + Private Shared ReadOnly s_aquariumContentsPropertyKey As DependencyPropertyKey = + DependencyProperty.RegisterReadOnly( + name:="AquariumContents", + propertyType:=GetType(List(Of FrameworkElement)), + ownerType:=GetType(Aquarium), + typeMetadata:=New FrameworkPropertyMetadata()) + 'typeMetadata:=New FrameworkPropertyMetadata(New List(Of FrameworkElement))) + + ' Store the dependency property identifier as a static member of the class. + Public Shared ReadOnly AquariumContentsProperty As DependencyProperty = + s_aquariumContentsPropertyKey.DependencyProperty + + ' Set the default collection value in a class constructor. + Public Sub New() + SetValue(s_aquariumContentsPropertyKey, New List(Of FrameworkElement)()) + End Sub + + ' Declare a read-only property. + Public ReadOnly Property AquariumContents As List(Of FrameworkElement) + Get + Return CType(GetValue(AquariumContentsProperty), List(Of FrameworkElement)) + End Get + End Property + End Class + + Public Class Fish + Inherits FrameworkElement + End Class + ' + + Public Class ReadWriteAquariumContents + + Public Shared Sub InitializeAquariums() + Dim aquarium1 As New Aquarium() + Dim aquarium2 As New Aquarium() + aquarium1.AquariumContents.Add(New Fish()) + aquarium2.AquariumContents.Add(New Fish()) + aquarium2.AquariumContents = New List(Of FrameworkElement)() + MessageBox.Show($"Aquarium1 contains {aquarium1.AquariumContents.Count} fish{Environment.NewLine}" + + $"Aquarium2 contains {aquarium2.AquariumContents.Count} fish") + End Sub + + ' + Public Class Aquarium + Inherits DependencyObject + + ' Register a dependency property with the specified property name, + ' property type, and owner type. + Private Shared ReadOnly s_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)()) + End Sub + + ' Declare a read-write property. + Public Property AquariumContents As List(Of FrameworkElement) + Get + Return CType(GetValue(AquariumContentsProperty), List(Of FrameworkElement)) + End Get + Set + SetValue(AquariumContentsProperty, Value) + End Set + End Property + End Class + ' + + Public Class Fish + Inherits FrameworkElement + End Class + + End Class + + Public Class FreezableCollectionAquarium + + Public Shared Sub InitializeAquariums() + Dim aquarium1 As New Aquarium() + Dim aquarium2 As New Aquarium() + aquarium1.AquariumContents.Add(New Fish()) + aquarium2.AquariumContents.Add(New Fish()) + MessageBox.Show($"Aquarium1 contains {aquarium1.AquariumContents.Count} fish{Environment.NewLine}" + + $"Aquarium2 contains {aquarium2.AquariumContents.Count} fish") + End Sub + + ' + Public Class Aquarium + Inherits DependencyObject + + ' Register a dependency property with the specified property name, + ' property type, and owner type. + Private Shared ReadOnly s_aquariumContentsPropertyKey As DependencyPropertyKey = + DependencyProperty.RegisterReadOnly( + name:="AquariumContents", + propertyType:=GetType(FreezableCollection(Of FrameworkElement)), + ownerType:=GetType(Aquarium), + typeMetadata:=New FrameworkPropertyMetadata()) + + ' Store the dependency property identifier as a static member of the class. + Public Shared ReadOnly AquariumContentsProperty As DependencyProperty = + s_aquariumContentsPropertyKey.DependencyProperty + + ' Set the default collection value in a class constructor. + Public Sub New() + SetValue(s_aquariumContentsPropertyKey, New FreezableCollection(Of FrameworkElement)()) + End Sub + + ' Declare a read-only property. + Public ReadOnly Property AquariumContents As FreezableCollection(Of FrameworkElement) + Get + Return CType(GetValue(AquariumContentsProperty), FreezableCollection(Of FrameworkElement)) + End Get + End Property + End Class + ' + + Public Class Fish + Inherits FrameworkElement + End Class + + End Class + +End Namespace diff --git a/dotnet-desktop-guide/net/wpf/toc.yml b/dotnet-desktop-guide/net/wpf/toc.yml index 86cf216..cc3d519 100644 --- a/dotnet-desktop-guide/net/wpf/toc.yml +++ b/dotnet-desktop-guide/net/wpf/toc.yml @@ -86,6 +86,8 @@ items: href: properties/dependency-property-value-precedence.md - name: Register an attached property href: properties/how-to-register-an-attached-property.md + - name: Collection-type dependency properties + href: properties/collection-type-dependency-properties.md - name: Resources items: - name: Overview diff --git a/redirects_generator/definitions.json b/redirects_generator/definitions.json index 083db02..3ff61d6 100644 --- a/redirects_generator/definitions.json +++ b/redirects_generator/definitions.json @@ -334,6 +334,11 @@ "SourceUrl": "/dotnet/desktop/wpf/advanced/how-to-register-an-attached-property?view=netframeworkdesktop-4.8", "TargetUrl": "/dotnet/desktop/wpf/properties/how-to-register-an-attached-property?view=netdesktop-5.0" }, + { + "Redirect": "TwoWay", + "SourceUrl": "/dotnet/desktop/wpf/advanced/collection-type-dependency-properties?view=netframeworkdesktop-4.8", + "TargetUrl": "/dotnet/desktop/wpf/properties/collection-type-dependency-properties?view=netdesktop-5.0" + }, // Systems - XAML {