Właściwości tylko do odczytu w WPF

Czasami w WPF zachodzi potrzeba stworzenia dependency property ale tylko do odczytu. Zwykłą właściwość bardzo łatwo zaimplementować tzn.:

public double Area
{
  get 
  {
      return _width*_height;
  }
}

Jeśli korzystamy z binding’u danych, wtedy powyższe rozwiązanie jest niewystarczające i należy skorzystać z dependnecy property. Dla przypomnienia, standardowa deklaracja wygląda następująco:

public class MyStateControl : ButtonBase
{
  public MyStateControl() : base() { }
  public Boolean State
  {
    get { return (Boolean)this.GetValue(StateProperty); }
    set { this.SetValue(StateProperty, value); } 
  }
  public static readonly DependencyProperty StateProperty = DependencyProperty.Register(
    "State", typeof(Boolean), typeof(MyStateControl),new PropertyMetadata(false));
}

Ktoś mógłby zaproponować takie rozwiązanie:

public class MyStateControl : ButtonBase
{
  public MyStateControl() : base() { }
  public Boolean State
  {
    get { return (Boolean)this.GetValue(StateProperty); }
  }
  public static readonly DependencyProperty StateProperty = DependencyProperty.Register(
    "State", typeof(Boolean), typeof(MyStateControl),new PropertyMetadata(false));
}

Niestety powyższy kod nie zabroni nikomu zmieniania StateProperty. Powyższe gettery\settery to wyłącznie wrapper C#. WPF czy inni programiści, wciąż mogą używać MyStateControl.StateProperty.SetValue w celu modyfikacji danych.

Prawidłowa implementacja powinna używać DependencyPropertyKey  oraz metodę RegisterReadOnly:

internal static readonly DependencyPropertyKey AquariumSizeKey = DependencyProperty.RegisterReadOnly(
  "AquariumSize",
  typeof(double),
  typeof(Aquarium),
  new PropertyMetadata(double.NaN)
);
public static readonly DependencyProperty AquariumSizeProperty =
  AquariumSizeKey.DependencyProperty;
public double AquariumSize
{
  get { return (double)GetValue(AquariumSizeProperty); }
}

Należy pamiętać aby DependencyPropertyKey było typu internal – dzięki temu, nie będzie można zmodyfikować właściwości z spoza klasy. Publiczny dostęp ma wyłącznie DependencyProperty ale próba modyfikacji zakończy się zawsze wyjątkiem. Jedyny zatem sposób na ustawienie wartości to użycie DependencyPropertyKey, który z kolei ma dostęp internal:

this.SetValue(AquariumSizeKey,size);

Poniższy kod z kolei wywoła wyjątek:

this.SetValue(AquariumSizeProperty,size);

Leave a Reply

Your email address will not be published.