Sdílet prostřednictvím


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é