Udostępnij za pośrednictwem


Zabezpieczenia właściwości zależności (WPF .NET)

Dostępność właściwości zależności odczytu i zapisu za pośrednictwem systemu właściwości Windows Presentation Foundation (WPF) skutecznie sprawia, że są one właściwościami publicznymi. W związku z tym nie można zagwarantować zabezpieczeń wartości właściwości zależności odczytu i zapisu. System właściwości WPF zapewnia większe bezpieczeństwo właściwości zależności tylko do odczytu, dzięki czemu można ograniczyć dostęp do zapisu.

Dostęp i zabezpieczenia otoek właściwości

Otoka właściwości środowiska uruchomieniowego języka wspólnego (CLR) jest zwykle zawarta w implementacjach właściwości zależności odczytu i zapisu w celu uproszczenia pobierania lub ustawiania wartości właściwości. W przypadku dołączeń otoka właściwości CLR jest metodą wygody, która implementuje GetValue wywołania statyczne i SetValue współdziałające z podstawową właściwością zależności. Zasadniczo otoka właściwości CLR uwidacznia właściwość zależności jako właściwość CLR wspieraną przez właściwość zależności, a nie pole prywatne.

Zastosowanie mechanizmów zabezpieczeń i ograniczenie dostępu do otoki właściwości CLR może uniemożliwić użycie metody wygody, ale te techniki nie zapobiegną bezpośrednim wywołaniom metody GetValue lub SetValue. Innymi słowy, właściwość zależności odczytu i zapisu jest zawsze dostępna za pośrednictwem systemu właściwości WPF. Jeśli implementujesz właściwość zależności odczytu i zapisu, unikaj ograniczania dostępu do otoki właściwości CLR. Zamiast tego zadeklaruj otokę właściwości CLR jako element członkowski publiczny, aby osoby wywołujące znały prawdziwy poziom dostępu właściwości zależności.

Ekspozycja systemu właściwości zależności

System właściwości WPF zapewnia dostęp do właściwości zależności odczytu i zapisu za pośrednictwem jego DependencyProperty identyfikatora. Identyfikator można używać w GetValue wywołaniach i SetValue . Nawet jeśli pole identyfikatora statycznego jest niepubliczne, kilka aspektów systemu właściwości zwróci DependencyProperty wartość , ponieważ istnieje w wystąpieniu klasy lub klasy pochodnej. Na przykład GetLocalValueEnumerator metoda zwraca identyfikatory wystąpień właściwości zależności z lokalnie ustawioną wartością. Ponadto można zastąpić metodę wirtualną OnPropertyChanged w celu odbierania danych zdarzeń, które będą zgłaszać DependencyProperty identyfikator właściwości zależności, które uległy zmianie. Aby osoby wywołujące wiedziały o rzeczywistym poziomie dostępu właściwości zależności read-write, zadeklaruj pole identyfikatora jako element członkowski publiczny.

Uwaga

Mimo że deklarowanie pola private identyfikatora właściwości zależności zmniejsza liczbę sposobów dostępności właściwości zależności odczytu i zapisu, właściwość nie będzie prywatna zgodnie z definicją języka CLR.

Zabezpieczenia weryfikacji

Demand Zastosowanie elementu do elementu ValidateValueCallback i oczekuje, że weryfikacja zakończy się niepowodzeniem po Demand awarii, nie jest odpowiednim mechanizmem zabezpieczeń ograniczania zmian wartości właściwości. Ponadto nowe unieważnienie wartości wymuszone za pomocą programu ValidateValueCallback może zostać pominięte przez złośliwych wywołań, jeśli te osoby wywołujące działają w domenie aplikacji.

Dostęp do właściwości zależności tylko do odczytu

Aby ograniczyć dostęp, zarejestruj właściwość jako właściwość zależności tylko do odczytu, wywołując metodę RegisterReadOnly . Metoda RegisterReadOnly zwraca DependencyPropertyKeywartość , którą można przypisać do pola klasy innej niż publiczna. W przypadku właściwości zależności tylko do odczytu system właściwości WPF zapewni dostęp do zapisu tylko tym, którzy mają odwołanie do DependencyPropertyKeyobiektu . Aby zilustrować to zachowanie, następujący kod testowy:

  • Tworzy wystąpienie klasy, która implementuje zarówno właściwości zależności read-write, jak i tylko do odczytu.
  • private Przypisuje modyfikator dostępu do każdego identyfikatora.
  • Implementuje get tylko metody dostępu.
  • GetLocalValueEnumerator Używa metody w celu uzyskania dostępu do podstawowych właściwości zależności za pośrednictwem systemu właściwości WPF.
  • Wywołuje GetValue metodę i SetValue przetestuj dostęp do każdej wartości właściwości zależności.
    /// <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

Zobacz też