mirror of
https://github.com/Stone-Red-Code/docs-desktop.git
synced 2026-09-04 09:06:04 +02:00
merge main branch
This commit is contained in:
@@ -564,6 +564,22 @@
|
||||
{
|
||||
"source_path": "dotnet-desktop-guide/framework/wpf/properties/read-only-dependency-properties.md",
|
||||
"redirect_url": "/dotnet/desktop/wpf/advanced/read-only-dependency-properties?view=netframeworkdesktop-4.8"
|
||||
},
|
||||
{
|
||||
"source_path": "dotnet-desktop-guide/net/wpf/advanced/framework-property-metadata.md",
|
||||
"redirect_url": "/dotnet/desktop/wpf/properties/framework-property-metadata?view=netdesktop-6.0"
|
||||
},
|
||||
{
|
||||
"source_path": "dotnet-desktop-guide/framework/wpf/properties/framework-property-metadata.md",
|
||||
"redirect_url": "/dotnet/desktop/wpf/advanced/framework-property-metadata?view=netframeworkdesktop-4.8"
|
||||
},
|
||||
{
|
||||
"source_path": "dotnet-desktop-guide/net/wpf/advanced/dependency-property-security.md",
|
||||
"redirect_url": "/dotnet/desktop/wpf/properties/dependency-property-security?view=netdesktop-6.0"
|
||||
},
|
||||
{
|
||||
"source_path": "dotnet-desktop-guide/framework/wpf/properties/dependency-property-security.md",
|
||||
"redirect_url": "/dotnet/desktop/wpf/advanced/dependency-property-security?view=netframeworkdesktop-4.8"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ Since most existing dependency properties aren't virtual properties, their inher
|
||||
|
||||
- For a <xref:System.Windows.PropertyMetadata.DefaultValue%2A>, the new value will replace the existing default value. If you don't specify a `DefaultValue` in the override metadata, the value comes from the nearest ancestor that specified `DefaultValue` in metadata.
|
||||
|
||||
- For a <xref:System.Windows.PropertyMetadata.PropertyChangedCallback%2A>, the default merge logic stores all `PropertyChangedCallback` values in a table, and all are invoked on a property change. The callback order is determined by class depth, where the callback registered by the base class in the hierarchy runs first.
|
||||
- For a <xref:System.Windows.PropertyMetadata.PropertyChangedCallback%2A>, the default merge logic stores all `PropertyChangedCallback` values in a table, and all are invoked on a property change. The callback order is determined by class depth, where a callback registered by the base class in the hierarchy would run first.
|
||||
|
||||
- For a <xref:System.Windows.PropertyMetadata.CoerceValueCallback%2A>, the new value will replace the existing `CoerceValueCallback` value. If you don't specify a `CoerceValueCallback` in the override metadata, the value comes from the nearest ancestor that specified `CoerceValueCallback` in metadata.
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
---
|
||||
title: "Dependency property security"
|
||||
description: Learn about the dependency property accessibility and security in Windows Presentation Foundation (WPF).
|
||||
ms.date: "12/03/2021"
|
||||
dev_langs:
|
||||
- "csharp"
|
||||
- "vb"
|
||||
helpviewer_keywords:
|
||||
- "wrappers [WPF], access"
|
||||
- "wrappers [WPF], security"
|
||||
- "dependency properties [WPF], security"
|
||||
- "security [WPF], wrappers"
|
||||
- "validation [WPF], dependency properties"
|
||||
- "dependency properties [WPF], access"
|
||||
- "security [WPF], dependency properties"
|
||||
---
|
||||
<!-- The acrolinx score was 92 on 12/03/2021-->
|
||||
|
||||
# Dependency property security (WPF .NET)
|
||||
|
||||
The accessibility of read-write dependency properties through the Windows Presentation Foundation (WPF) property system effectively makes them public properties. As a result, it's not possible to make security guarantees about read-write dependency property values. The WPF property system provides more security for read-only dependency properties so that you can restrict write access.
|
||||
|
||||
[!INCLUDE [desktop guide under construction](../../includes/desktop-guide-preview-note.md)]
|
||||
|
||||
## Access and security of property wrappers
|
||||
|
||||
A common language runtime (CLR) property wrapper is usually included in read-write dependency property implementations to simplify getting or setting property values. If included, the CLR property wrapper is a convenience method that implements the <xref:System.Windows.DependencyObject.GetValue%2A> and <xref:System.Windows.DependencyObject.SetValue%2A> static calls that interact with the underlying dependency property. Essentially, a CLR property wrapper exposes a dependency property as a CLR property backed by a dependency property rather than a private field.
|
||||
|
||||
Applying security mechanisms and restricting access to the CLR property wrapper might prevent usage of the convenience method, but those techniques won't prevent direct calls to `GetValue` or `SetValue`. In other words, a read-write dependency property is always accessible through the WPF property system. If you're implementing a read-write dependency property, avoid restricting access to the CLR property wrapper. Instead, declare the CLR property wrapper as a public member so callers are aware of the true access level of the dependency property.
|
||||
|
||||
## Property system exposure of dependency properties
|
||||
|
||||
The WPF property system provides access to a read-write dependency property through its <xref:System.Windows.DependencyProperty> identifier. The identifier is usable in <xref:System.Windows.DependencyObject.GetValue%2A> and <xref:System.Windows.DependencyObject.SetValue%2A> calls. Even if the static identifier field is non-public, several aspects of the property system will return a `DependencyProperty` as it exists on an instance of a class or derived class. For example, the <xref:System.Windows.DependencyObject.GetLocalValueEnumerator%2A> method returns identifiers for dependency property instances with a locally set value. Also, you can override the <xref:System.Windows.DependencyObject.OnPropertyChanged%2A> virtual method to receive event data that will report the `DependencyProperty` identifier for dependency properties that have changed value. To make callers aware of the true access level of a read-write dependency property, declare its identifier field as a public member.
|
||||
|
||||
> [!NOTE]
|
||||
> Although declaring a dependency property identifier field as `private` reduces the number of ways that a read-write dependency property is accessible, the property won't be [private](/dotnet/csharp/language-reference/keywords/private) according to the CLR language definition.
|
||||
|
||||
### Validation security
|
||||
|
||||
Applying a <xref:System.Security.IStackWalk.Demand%2A> to a <xref:System.Windows.DependencyProperty.ValidateValueCallback%2A> and expecting validation to fail on `Demand` failure, isn't an adequate security mechanism for restricting property value changes. Also, new value invalidation enforced through `ValidateValueCallback` can be suppressed by malicious callers, if those callers are operating within the application domain.
|
||||
|
||||
## Access to read-only dependency properties
|
||||
|
||||
To restrict access, register your property as a read-only dependency property by calling the <xref:System.Windows.DependencyProperty.RegisterReadOnly%2A> method. The `RegisterReadOnly` method returns a <xref:System.Windows.DependencyPropertyKey>, which you can assign to a non-public class field. For read-only dependency properties, the WPF property system will only provide write access to those who have a reference to the `DependencyPropertyKey`. To illustrate this behavior, the following test code:
|
||||
|
||||
- Instantiates a class that implements both read-write and read-only dependency properties.
|
||||
- Assigns a `private` access modifier to each identifier.
|
||||
- Only implements `get` accessors.
|
||||
- Uses the <xref:System.Windows.DependencyObject.GetLocalValueEnumerator%2A> method to access the underlying dependency properties through the WPF property system.
|
||||
- Calls <xref:System.Windows.DependencyObject.GetValue%2A> and <xref:System.Windows.DependencyObject.SetValue%2A> to test access to each dependency property value.
|
||||
|
||||
:::code language="csharp" source="./snippets/dependency-property-security/csharp/MainWindow.xaml.cs" id="DependencyPropertyAccessTests":::
|
||||
:::code language="vb" source="./snippets/dependency-property-security/vb/MainWindow.xaml.vb" id="DependencyPropertyAccessTests":::
|
||||
|
||||
## See also
|
||||
|
||||
- <xref:System.Windows.DependencyProperty>
|
||||
- <xref:System.Windows.DependencyObject.GetLocalValueEnumerator%2A>
|
||||
- <xref:System.Windows.DependencyObject.OnPropertyChanged%2A>
|
||||
- [Custom dependency properties](custom-dependency-properties.md)
|
||||
- [Implement a Dependency property](how-to-implement-a-dependency-property.md)
|
||||
@@ -0,0 +1,79 @@
|
||||
---
|
||||
title: "Framework property metadata"
|
||||
description: Learn how to set framework property metadata for a dependency property in Windows Presentation Foundation (WPF).
|
||||
ms.date: "11/20/2021"
|
||||
helpviewer_keywords:
|
||||
- "metadata [WPF], framework properties"
|
||||
- "framework property metadata [WPF]"
|
||||
---
|
||||
<!-- The acrolinx score was 92 on 11/20/2021-->
|
||||
|
||||
# Framework property metadata (WPF .NET)
|
||||
|
||||
You can set framework property metadata options for dependency properties at the Windows Presentation Foundation (WPF) framework level. The WPF framework level designation applies when WPF presentation APIs and executables handle rendering and data binding. Presentation APIs and executables query the <xref:System.Windows.FrameworkPropertyMetadata> 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.
|
||||
|
||||
## Framework property metadata categories
|
||||
|
||||
<xref:System.Windows.FrameworkPropertyMetadata> falls into these categories:
|
||||
|
||||
- Metadata that affects the layout of an element, specifically the <xref:System.Windows.FrameworkPropertyMetadata.AffectsArrange%2A>, <xref:System.Windows.FrameworkPropertyMetadata.AffectsMeasure%2A>, and <xref:System.Windows.FrameworkPropertyMetadata.AffectsRender%2A> metadata flags. You might set those flags if your dependency property implementation affects a visual aspect and you're implementing <xref:System.Windows.FrameworkElement.MeasureOverride%2A> or <xref:System.Windows.FrameworkElement.ArrangeOverride%2A> in your class. The `MeasureOverride` and `ArrangeOverride` methods provide implementation-specific behavior and rendering information to the layout system. When `AffectsArrange`, `AffectsMeasure`, or `AffectsRender` are set to `true` in the metadata of a dependency property and its effective value changes, the WPF property system will initiate a request to invalidate the element's visuals to trigger a redraw.
|
||||
|
||||
- Metadata that affects the layout of the parent element of an element, specifically the <xref:System.Windows.FrameworkPropertyMetadata.AffectsParentArrange%2A> and <xref:System.Windows.FrameworkPropertyMetadata.AffectsParentMeasure%2A> metadata flags. Examples of WPF dependency properties that set these flags are <xref:System.Windows.Documents.FixedPage.Left%2A?displayProperty=nameWithType> and <xref:System.Windows.Documents.Paragraph.KeepWithNext%2A?displayProperty=nameWithType>.
|
||||
|
||||
- Property value inheritance metadata, specifically the <xref:System.Windows.FrameworkPropertyMetadata.Inherits%2A> and <xref:System.Windows.FrameworkPropertyMetadata.OverridesInheritanceBehavior%2A> metadata flags. By default, dependency properties don't inherit values. <xref:System.Windows.FrameworkPropertyMetadata.OverridesInheritanceBehavior%2A> allows the pathway of inheritance to also travel into a visual tree, which is necessary for some control compositing scenarios. For more information, see [Property value inheritance](/dotnet/desktop/wpf/advanced/property-value-inheritance?view=netframeworkdesktop-4.8&preserve-view=true).
|
||||
|
||||
> [!NOTE]
|
||||
> The term "inherits" in the context of property values is specific to dependency properties, and doesn't directly relate to managed code types and member inheritance through derived types. In the context of dependency properties, it means that child elements can inherit dependency property values from parent elements.
|
||||
|
||||
- Data binding metadata, specifically the <xref:System.Windows.FrameworkPropertyMetadata.BindsTwoWayByDefault%2A> and <xref:System.Windows.FrameworkPropertyMetadata.IsNotDataBindable%2A> metadata flags. By default, dependency properties in the WPF framework support one-way binding. Consider setting two-way binding as the default for properties that report state *and* are modifiable by user action, for example <xref:System.Windows.Controls.Primitives.Selector.IsSelected>. Also, consider setting two-way binding as the default when users of a control expect a property to implement it, for example [TextBox.Text](<xref:System.Windows.Controls.TextBox.Text>). `BindsTwoWayByDefault` only affects the default binding mode. To edit the data flow direction of a binding, set [Binding.Mode](<xref:System.Windows.Data.Binding.Mode>). You can use `IsNotDataBindable` to disable data binding when there's no use case for it. For more information on data bindings, see [Data binding overview](/dotnet/desktop/wpf/advanced/data-binding-overview?view=netframeworkdesktop-4.8&preserve-view=true).
|
||||
|
||||
- Journaling metadata, specifically the <xref:System.Windows.FrameworkPropertyMetadata.Journal%2A> metadata flag. The default value of the `Journal` flag is only `true` for a some dependency properties, such as <xref:System.Windows.Controls.Primitives.Selector.SelectedIndex>. User input controls should set the `Journal` flag for properties whose values hold user selections that need to be stored. The `Journal` flag is read by applications or services that support journaling, including WPF journaling services. For information on storing navigation steps, see [Navigation overview](/dotnet/desktop/wpf/app-development/navigation-overview?view=netframeworkdesktop-4.8&preserve-view=true).
|
||||
|
||||
<xref:System.Windows.FrameworkPropertyMetadata> derives directly from <xref:System.Windows.UIPropertyMetadata>, and implements the flags discussed here. Unless specifically set, `FrameworkPropertyMetadata` flags have a default value of `false`.
|
||||
|
||||
## Reading FrameworkPropertyMetadata
|
||||
|
||||
To retrieve metadata for a dependency property, call <xref:System.Windows.DependencyProperty.GetMetadata%2A> on the <xref:System.Windows.DependencyProperty> identifier. The `GetMetadata` call returns a `PropertyMetadata` object. If you need to query framework metadata values cast `PropertyMetadata` to <xref:System.Windows.FrameworkPropertyMetadata>.
|
||||
|
||||
## Specifying FrameworkPropertyMetadata
|
||||
|
||||
When you register a dependency property, you have the option to create and assign metadata to it. The metadata object that you assign can be <xref:System.Windows.PropertyMetadata> or one of its derived classes, like <xref:System.Windows.FrameworkPropertyMetadata>. Choose `FrameworkPropertyMetadata` for dependency properties that rely on WPF presentation APIs and executables for rendering and data binding. A more advanced option is to derive from `FrameworkPropertyMetadata` to create a custom metadata reporting class with more flags. Or, you might use <xref:System.Windows.UIPropertyMetadata> for non-framework properties that affect UI rendering.
|
||||
|
||||
Although metadata options are typically set during registration of a new dependency property, you can respecify them in <xref:System.Windows.DependencyProperty.OverrideMetadata%2A> or <xref:System.Windows.DependencyProperty.AddOwner%2A> calls. When overriding metadata, always override with the same metadata type that was used during property registration.
|
||||
|
||||
The property characteristics that are exposed by `FrameworkPropertyMetadata` are sometimes referred to as *flags*. If you're creating a `FrameworkPropertyMetadata` instance, there are two ways to populate flag values:
|
||||
|
||||
1. Set the flags on an instance of the <xref:System.Windows.FrameworkPropertyMetadataOptions> enumeration type. `FrameworkPropertyMetadataOptions` lets you specify metadata flags in bitwise OR combination. Then, instantiate `FrameworkPropertyMetadata` using a constructor that has a `FrameworkPropertyMetadataOptions` parameter, and pass in your `FrameworkPropertyMetadataOptions` instance. To change metadata flags after passing `FrameworkPropertyMetadataOptions` into the <xref:System.Windows.FrameworkPropertyMetadata> constructor, change the corresponding property on the new `FrameworkPropertyMetadata` instance. For example, if you set the <xref:System.Windows.FrameworkPropertyMetadataOptions.NotDataBindable?displayProperty=nameWithType> flag, you can undo that by setting <xref:System.Windows.FrameworkPropertyMetadata.IsNotDataBindable%2A?displayProperty=nameWithType> to `false`.
|
||||
|
||||
1. Instantiate `FrameworkPropertyMetadata` using a constructor that doesn't have a `FrameworkPropertyMetadataOptions` parameter, and then set the applicable <xref:System.Boolean> flags on `FrameworkPropertyMetadata`. Set flag values before associating your `FrameworkPropertyMetadata` instance with a dependency property, otherwise you'll get an <xref:System.InvalidOperationException>.
|
||||
|
||||
## Metadata override behavior
|
||||
|
||||
When you override framework property metadata, changed metadata values either replace or are merged with the original values:
|
||||
|
||||
- For a <xref:System.Windows.PropertyMetadata.PropertyChangedCallback%2A>, the default merge logic retains previous `PropertyChangedCallback` values in a table, and all are invoked on a property change. The callback order is determined by class depth, where a callback registered by the base class in the hierarchy would run first. Inherited callbacks run only once, and are owned by the class that added them into metadata.
|
||||
|
||||
- For a <xref:System.Windows.PropertyMetadata.DefaultValue%2A>, the new value will replace the existing default value. If you don't specify a `DefaultValue` in the override metadata and if the existing <xref:System.Windows.FrameworkPropertyMetadata> has the `Inherits` flag set, then the default value comes from the nearest ancestor that specified `DefaultValue` in metadata.
|
||||
|
||||
- For a <xref:System.Windows.PropertyMetadata.CoerceValueCallback%2A>, the new value will replace an existing `CoerceValueCallback` value. If you don't specify a `CoerceValueCallback` in the override metadata, the value comes from the nearest ancestor in the inheritance chain that specified a `CoerceValueCallback`.
|
||||
|
||||
- For `FrameworkPropertyMetadata` non-inherited flags, you can override the default `false` value with a `true` value. However, you can only override a `true` value with a `false` value for <xref:System.Windows.FrameworkPropertyMetadata.Inherits%2A>, <xref:System.Windows.FrameworkPropertyMetadata.Journal%2A>, <xref:System.Windows.FrameworkPropertyMetadata.OverridesInheritanceBehavior%2A>, and <xref:System.Windows.FrameworkPropertyMetadata.SubPropertiesDoNotAffectRender%2A>.
|
||||
|
||||
> [!NOTE]
|
||||
> The default merge logic is implemented by the <xref:System.Windows.PropertyMetadata.Merge%2A> method. You can specify custom merge logic in a derived class that inherits a dependency property, by overriding `Merge` in that class.
|
||||
|
||||
## See also
|
||||
|
||||
- <xref:System.Windows.PropertyMetadata>
|
||||
- <xref:System.Windows.DependencyProperty.GetMetadata%2A>
|
||||
- <xref:System.Windows.DependencyProperty.OverrideMetadata%2A>
|
||||
- <xref:System.Windows.DependencyProperty.AddOwner%2A>
|
||||
- [Dependency Property Metadata](dependency-property-metadata.md)
|
||||
- [Dependency Properties Overview](dependency-properties-overview.md)
|
||||
- [Custom Dependency Properties](custom-dependency-properties.md)
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace CodeSampleCsharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for App.xaml
|
||||
/// </summary>
|
||||
public partial class App : Application
|
||||
{
|
||||
}
|
||||
}
|
||||
+10
@@ -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)
|
||||
)]
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<UseWPF>true</UseWPF>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Properties\Resources.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
<Window x:Class="CodeSampleCsharp.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="Dependency property security" Height="100" Width="400">
|
||||
</Window>
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
|
||||
namespace CodeSampleCsharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for MainWindow.xaml.
|
||||
/// </summary>
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
DependencyPropertyAccessTests();
|
||||
}
|
||||
|
||||
//<DependencyPropertyAccessTests>
|
||||
/// <summary>
|
||||
/// Test get/set access to dependency properties exposed through the WPF property system.
|
||||
/// </summary>
|
||||
public static void DependencyPropertyAccessTests()
|
||||
{
|
||||
// Instantiate a class that implements read-write and read-only dependency properties.
|
||||
Aquarium _aquarium = new();
|
||||
// Access each dependency property using the LocalValueEnumerator method.
|
||||
LocalValueEnumerator localValueEnumerator = _aquarium.GetLocalValueEnumerator();
|
||||
while (localValueEnumerator.MoveNext())
|
||||
{
|
||||
DependencyProperty dp = localValueEnumerator.Current.Property;
|
||||
string dpType = dp.ReadOnly ? "read-only" : "read-write";
|
||||
// Test read access.
|
||||
Debug.WriteLine($"Attempting to get a {dpType} dependency property value...");
|
||||
Debug.WriteLine($"Value ({dpType}): {(int)_aquarium.GetValue(dp)}");
|
||||
// Test write access.
|
||||
try
|
||||
{
|
||||
Debug.WriteLine($"Attempting to set a {dpType} dependency property value to 2...");
|
||||
_aquarium.SetValue(dp, 2);
|
||||
}
|
||||
catch (InvalidOperationException e)
|
||||
{
|
||||
Debug.WriteLine(e.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Debug.WriteLine($"Value ({dpType}): {(int)_aquarium.GetValue(dp)}");
|
||||
}
|
||||
}
|
||||
|
||||
// Test output:
|
||||
|
||||
// Attempting to get a read-write dependency property value...
|
||||
// Value (read-write): 1
|
||||
// Attempting to set a read-write dependency property value to 2...
|
||||
// Value (read-write): 2
|
||||
|
||||
// Attempting to get a read-only dependency property value...
|
||||
// Value (read-only): 1
|
||||
// Attempting to set a read-only dependency property value to 2...
|
||||
// 'FishCountReadOnly' property was registered as read-only
|
||||
// and cannot be modified without an authorization key.
|
||||
// Value (read-only): 1
|
||||
}
|
||||
}
|
||||
|
||||
public class Aquarium : DependencyObject
|
||||
{
|
||||
public Aquarium()
|
||||
{
|
||||
// Assign locally-set values.
|
||||
SetValue(FishCountProperty, 1);
|
||||
SetValue(FishCountReadOnlyPropertyKey, 1);
|
||||
}
|
||||
|
||||
// Failed attempt to restrict write-access by assigning the
|
||||
// DependencyProperty identifier to a non-public field.
|
||||
private static readonly DependencyProperty FishCountProperty =
|
||||
DependencyProperty.Register(
|
||||
name: "FishCount",
|
||||
propertyType: typeof(int),
|
||||
ownerType: typeof(Aquarium),
|
||||
typeMetadata: new PropertyMetadata());
|
||||
|
||||
// Successful attempt to restrict write-access by assigning the
|
||||
// DependencyPropertyKey to a non-public field.
|
||||
private static readonly DependencyPropertyKey FishCountReadOnlyPropertyKey =
|
||||
DependencyProperty.RegisterReadOnly(
|
||||
name: "FishCountReadOnly",
|
||||
propertyType: typeof(int),
|
||||
ownerType: typeof(Aquarium),
|
||||
typeMetadata: new PropertyMetadata());
|
||||
|
||||
// Declare public get accessors.
|
||||
public int FishCount => (int)GetValue(FishCountProperty);
|
||||
public int FishCountReadOnly => (int)GetValue(FishCountReadOnlyPropertyKey.DependencyProperty);
|
||||
}
|
||||
//</DependencyPropertyAccessTests>
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace CodeSampleCsharp.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CodeSampleCsharp.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
<Application x:Class="CodeSampleCsharp.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:CodeSampleCsharp"
|
||||
StartupUri="MainWindow.xaml">
|
||||
<Application.Resources>
|
||||
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
<Application x:Class="Application"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:CodeSampleVb"
|
||||
StartupUri="MainWindow.xaml">
|
||||
<Application.Resources>
|
||||
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
Class Application
|
||||
|
||||
' Application-level events, such as Startup, Exit, and DispatcherUnhandledException
|
||||
' can be handled in this file.
|
||||
|
||||
End Class
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
Imports System.Windows
|
||||
|
||||
'The ThemeInfo attribute describes where any theme specific and generic resource dictionaries can be found.
|
||||
'1st parameter: where theme specific resource dictionaries are located
|
||||
'(used if a resource is not found in the page,
|
||||
' or application resource dictionaries)
|
||||
|
||||
'2nd parameter: where the generic resource dictionary is located
|
||||
'(used if a resource is not found in the page,
|
||||
'app, and any theme specific resource dictionaries)
|
||||
<Assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)>
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<RootNamespace>CodeSampleVb</RootNamespace>
|
||||
<UseWPF>true</UseWPF>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Import Include="System.Windows" />
|
||||
<Import Include="System.Windows.Controls" />
|
||||
<Import Include="System.Windows.Data" />
|
||||
<Import Include="System.Windows.Documents" />
|
||||
<Import Include="System.Windows.Input" />
|
||||
<Import Include="System.Windows.Media" />
|
||||
<Import Include="System.Windows.Media.Imaging" />
|
||||
<Import Include="System.Windows.Navigation" />
|
||||
<Import Include="System.Windows.Shapes" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
<Window x:Class="CodeSampleVb.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="Dependency property security" Height="100" Width="400">
|
||||
</Window>
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
Namespace CodeSampleVb
|
||||
|
||||
' <summary>
|
||||
' Interaction logic for MainWindow.xaml.
|
||||
' </summary>
|
||||
Partial Public Class MainWindow
|
||||
Inherits Window
|
||||
|
||||
Public Sub New()
|
||||
InitializeComponent()
|
||||
DependencyPropertyAccessTests()
|
||||
End Sub
|
||||
|
||||
'<DependencyPropertyAccessTests>
|
||||
''' <summary>
|
||||
''' ' Test get/set access to dependency properties exposed through the WPF property system.
|
||||
''' </summary>
|
||||
Public Shared Sub DependencyPropertyAccessTests()
|
||||
' Instantiate a class that implements read-write and read-only dependency properties.
|
||||
Dim _aquarium As New Aquarium()
|
||||
' Access each dependency property using the LocalValueEnumerator method.
|
||||
Dim localValueEnumerator As LocalValueEnumerator = _aquarium.GetLocalValueEnumerator()
|
||||
While localValueEnumerator.MoveNext()
|
||||
Dim dp As DependencyProperty = localValueEnumerator.Current.[Property]
|
||||
Dim dpType As String = If(dp.[ReadOnly], "read-only", "read-write")
|
||||
' Test read access.
|
||||
Debug.WriteLine($"Attempting to get a {dpType} dependency property value...")
|
||||
Debug.WriteLine($"Value ({dpType}): {CInt(_aquarium.GetValue(dp))}")
|
||||
' Test write access.
|
||||
Try
|
||||
Debug.WriteLine($"Attempting to set a {dpType} dependency property value to 2...")
|
||||
_aquarium.SetValue(dp, 2)
|
||||
Catch e As InvalidOperationException
|
||||
Debug.WriteLine(e.Message)
|
||||
Finally
|
||||
Debug.WriteLine($"Value ({dpType}): {CInt(_aquarium.GetValue(dp))}")
|
||||
End Try
|
||||
End While
|
||||
|
||||
' Test output
|
||||
|
||||
' Attempting to get a read-write dependency property value...
|
||||
' Value (read-write): 1
|
||||
' Attempting to set a read-write dependency property value to 2...
|
||||
' Value (read-write): 2
|
||||
|
||||
' Attempting to get a read-only dependency property value...
|
||||
' Value (read-only): 1
|
||||
' Attempting to set a read-only dependency property value to 2...
|
||||
' 'FishCountReadOnly' property was registered as read-only
|
||||
' and cannot be modified without an authorization key.
|
||||
' Value (read-only): 1
|
||||
End Sub
|
||||
|
||||
End Class
|
||||
|
||||
Public Class Aquarium
|
||||
Inherits DependencyObject
|
||||
|
||||
Public Sub New()
|
||||
' Assign locally-set values.
|
||||
SetValue(FishCountProperty, 1)
|
||||
SetValue(FishCountReadOnlyPropertyKey, 1)
|
||||
End Sub
|
||||
|
||||
' Failed attempt to restrict write-access by assigning the
|
||||
' DependencyProperty identifier to a non-public field.
|
||||
Private Shared ReadOnly FishCountProperty As DependencyProperty =
|
||||
DependencyProperty.Register(
|
||||
name:="FishCount",
|
||||
propertyType:=GetType(Integer),
|
||||
ownerType:=GetType(Aquarium),
|
||||
typeMetadata:=New PropertyMetadata())
|
||||
|
||||
' Successful attempt to restrict write-access by assigning the
|
||||
' DependencyPropertyKey to a non-public field.
|
||||
Private Shared ReadOnly FishCountReadOnlyPropertyKey As DependencyPropertyKey =
|
||||
DependencyProperty.RegisterReadOnly(
|
||||
name:="FishCountReadOnly",
|
||||
propertyType:=GetType(Integer),
|
||||
ownerType:=GetType(Aquarium),
|
||||
typeMetadata:=New PropertyMetadata())
|
||||
|
||||
' Declare public get accessors.
|
||||
Public ReadOnly Property FishCount As Integer
|
||||
Get
|
||||
Return GetValue(FishCountProperty)
|
||||
End Get
|
||||
End Property
|
||||
|
||||
Public ReadOnly Property FishCountReadOnly As Integer
|
||||
Get
|
||||
Return GetValue(FishCountReadOnlyPropertyKey.DependencyProperty)
|
||||
End Get
|
||||
End Property
|
||||
|
||||
End Class
|
||||
'</DependencyPropertyAccessTests>
|
||||
|
||||
End Namespace
|
||||
@@ -96,6 +96,10 @@ items:
|
||||
href: properties/dependency-property-callbacks-and-validation.md
|
||||
- name: Read-only dependency properties
|
||||
href: properties/read-only-dependency-properties.md
|
||||
- name: Framework-property-metadata
|
||||
href: properties/framework-property-metadata.md
|
||||
- name: Dependency property security
|
||||
href: properties/dependency-property-security.md
|
||||
- name: Common tasks
|
||||
items:
|
||||
- name: Implement a dependency property
|
||||
|
||||
@@ -383,6 +383,14 @@
|
||||
"SourceUrl": "/dotnet/desktop/wpf/advanced/read-only-dependency-properties?view=netframeworkdesktop-4.8",
|
||||
"TargetUrl": "/dotnet/desktop/wpf/properties/read-only-dependency-properties?view=netdesktop-6.0"
|
||||
},
|
||||
{
|
||||
"SourceUrl": "/dotnet/desktop/wpf/advanced/framework-property-metadata?view=netframeworkdesktop-4.8",
|
||||
"TargetUrl": "/dotnet/desktop/wpf/properties/framework-property-metadata?view=netdesktop-6.0"
|
||||
},
|
||||
{
|
||||
"SourceUrl": "/dotnet/desktop/wpf/advanced/dependency-property-security?view=netframeworkdesktop-4.8",
|
||||
"TargetUrl": "/dotnet/desktop/wpf/properties/dependency-property-security?view=netdesktop-6.0"
|
||||
},
|
||||
|
||||
// Systems - XAML
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user