Zabezpečení vlastností závislostí (WPF .NET)
Přístupnost vlastností závislostí pro čtení i zápis prostřednictvím systému vlastností WINDOWS Presentation Foundation (WPF) je efektivně zpřístupňuje veřejnými vlastnostmi. V důsledku toho není možné zajistit záruky zabezpečení týkající se hodnot vlastností závislostí pro čtení i zápis. Systém vlastností WPF poskytuje větší zabezpečení pro vlastnosti závislostí jen pro čtení, abyste mohli omezit přístup k zápisu.
Přístup a zabezpečení obálky vlastností
Obálka vlastností CLR (Common Language Runtime) je obvykle součástí implementací vlastností závislostí pro čtení i zápis, které zjednodušují získávání nebo nastavování hodnot vlastností. Pokud je zahrnuta, obálka vlastností CLR je pohodlná metoda, která implementuje GetValue a SetValue statické volání, která pracují s podkladovou vlastností závislosti. Obálka vlastností CLR v podstatě zveřejňuje vlastnost závislosti jako vlastnost CLR, která je podporována vlastností závislosti místo soukromého pole.
Použití mechanismů zabezpečení a omezení přístupu k obálce vlastnosti CLR může zabraňovat použití usnadňující metody, ale tyto techniky nezabrání přímým voláním GetValue
nebo SetValue
. Jinými slovy, vlastnost závislostí pro čtení i zápis je vždy přístupná prostřednictvím systému vlastností WPF. Pokud implementujete vlastnost závislostí pro čtení i zápis, vyhněte se omezení přístupu k obálkě vlastností CLR. Místo toho deklarujte obálku vlastnosti CLR jako veřejného člena, aby volající věděli o skutečné úrovni přístupu vlastnosti závislosti.
Expozice systému vlastností pro vlastnosti závislostí
Systém vlastností WPF poskytuje přístup k vlastnosti závislosti pro čtení i zápis prostřednictvím svého identifikátoru DependencyProperty. Identifikátor je použitelný pro volání GetValue a SetValue. I když je pole statického identifikátoru neveřejné, několik aspektů systému vlastností vrátí DependencyProperty
, protože bude existovat na instanci třídy nebo odvozené třídy. Například metoda GetLocalValueEnumerator vrací identifikátory pro instance vlastností závislostí s místně nastavenou hodnotou. Můžete také přepsat virtuální metody OnPropertyChanged, abyste přijímali data událostí, která budou hlásit identifikátor DependencyProperty
pro vlastnosti závislosti, které změnily hodnotu. Chcete-li volajícím oznámit skutečnou úroveň přístupu vlastnosti závislosti pro čtení i zápis, deklarujte jeho pole identifikátoru jako veřejný člen.
Poznámka
Přestože deklarování pole identifikátoru vlastnosti závislosti jako private
snižuje počet způsobů, jak je přístupná vlastnost závislosti pro čtení i zápis, nebude tato vlastnost privátní podle definice jazyka CLR.
Zabezpečení ověřování
Použití Demand na ValidateValueCallback a očekávání, že ověření selže při selhání Demand
, není vhodným mechanismem zabezpečení pro omezení změn hodnot vlastností. Také nové vynucené zneplatnění hodnoty prostřednictvím ValidateValueCallback
může být potlačeno škodlivými volajícími, pokud tito volající operují v rámci domény aplikace.
Přístup k vlastnostem závislostí jen pro čtení
Pokud chcete omezit přístup, zaregistrujte vlastnost jako vlastnost závislostí jen pro čtení voláním metody RegisterReadOnly. Metoda RegisterReadOnly
vrátí hodnotu DependencyPropertyKey, kterou můžete přiřadit k neveřejnému poli třídy. Pro vlastnosti závislostí jen pro čtení bude systém vlastností WPF poskytovat přístup k zápisu pouze těm, kteří mají odkaz na DependencyPropertyKey
. K ilustraci tohoto chování použijte následující testovací kód:
- Vytvoří instanci třídy, která implementuje vlastnosti závislosti pro čtení i zápis a jen pro čtení.
- Přiřadí modifikátor přístupu
private
každému identifikátoru. - Implementuje pouze přístupové objekty
get
. - Používá GetLocalValueEnumerator metodu pro přístup k podkladovým vlastnostem závislostí prostřednictvím systému vlastností WPF.
- Volá GetValue a SetValue k otestování přístupu ke každé hodnotě vlastnosti závislosti.
/// <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);
}
''' <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
Viz také
.NET Desktop feedback