Segurança de propriedade de dependência (WPF .NET)

A acessibilidade das propriedades de dependência de leitura-gravação por meio do sistema de propriedades do Windows Presentation Foundation (WPF) efetivamente as torna propriedades públicas. Como resultado, não é possível fazer garantias de segurança sobre valores de propriedade de dependência de leitura-gravação. O sistema de propriedades WPF fornece mais segurança para propriedades de dependência somente leitura para que você possa restringir o acesso de gravação.

Importante

A documentação do Guia da Área de Trabalho para .NET 7 e .NET 6 está em construção.

Acesso e segurança dos invólucros de propriedade

Um wrapper de propriedade CLR (Common Language Runtime) geralmente é incluído em implementações de propriedade de dependência de leitura-gravação para simplificar a obtenção ou a definição de valores de propriedade. Se incluído, o wrapper de propriedade CLR é um método conveniente que implementa as GetValue chamadas estáticas e SetValue que interagem com a propriedade de dependência subjacente. Essencialmente, um wrapper de propriedade CLR expõe uma propriedade de dependência como uma propriedade CLR apoiada por uma propriedade de dependência em vez de um campo privado.

A aplicação de mecanismos de segurança e a restrição de acesso ao wrapper de propriedade CLR podem impedir o uso do método de conveniência, mas essas técnicas não impedirão chamadas diretas para GetValue ou SetValue. Em outras palavras, uma propriedade de dependência de leitura-gravação é sempre acessível por meio do sistema de propriedades WPF. Se você estiver implementando uma propriedade de dependência de leitura-gravação, evite restringir o acesso ao wrapper de propriedade CLR. Em vez disso, declare o wrapper de propriedade CLR como um membro público para que os chamadores estejam cientes do verdadeiro nível de acesso da propriedade de dependência.

Exposição das propriedades de dependência do sistema de propriedades

O sistema de propriedades WPF fornece acesso a uma propriedade de dependência de leitura-gravação por meio de seu DependencyProperty identificador. O identificador é utilizável em GetValue e SetValue chamadas. Mesmo que o campo identificador estático não seja público, vários aspectos do sistema de propriedades retornarão um DependencyProperty como ele existe em uma instância de uma classe ou classe derivada. Por exemplo, o GetLocalValueEnumerator método retorna identificadores para instâncias de propriedade de dependência com um valor definido localmente. Além disso, você pode substituir o método virtual para receber dados de evento que relatarão o OnPropertyChanged identificador de propriedades de dependência que alteraram o DependencyProperty valor. Para fazer com que os chamadores saibam o verdadeiro nível de acesso de uma propriedade de dependência de leitura-gravação, declare seu campo identificador como um membro público.

Observação

Embora declarar um campo identificador de propriedade de dependência como private reduz o número de maneiras pelas quais uma propriedade de dependência de leitura-gravação é acessível, a propriedade não será privada de acordo com a definição de linguagem CLR.

Segurança de validação

Aplicar a a a e ValidateValueCallback esperar que a Demand validação falhe em caso Demand de falha não é um mecanismo de segurança adequado para restringir alterações no valor da propriedade. Além disso, a nova invalidação de valor imposta pode ValidateValueCallback ser suprimida por chamadores mal-intencionados, se esses chamadores estiverem operando no domínio do aplicativo.

Acesso a propriedades de dependência somente leitura

Para restringir o acesso, registre sua propriedade como uma propriedade de dependência somente leitura chamando o RegisterReadOnly método. O RegisterReadOnly método retorna um , que você pode atribuir a um DependencyPropertyKeycampo de classe não público. Para propriedades de dependência somente leitura, o sistema de propriedades WPF só fornecerá acesso de gravação para aqueles que tiverem uma referência ao DependencyPropertyKey. Para ilustrar esse comportamento, o seguinte código de teste:

  • Instancia uma classe que implementa propriedades de dependência de leitura-gravação e somente leitura.
  • Atribui um private modificador de acesso a cada identificador.
  • Implementa apenas get acessadores.
  • Usa o GetLocalValueEnumerator método para acessar as propriedades de dependência subjacentes por meio do sistema de propriedades WPF.
  • Chamadas GetValue e SetValue para testar o acesso a cada valor de propriedade de dependência.
    /// <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

Confira também