Przegląd Obiekty Freezable

W tym temacie opisano sposób efektywnego używania i tworzenia Freezable obiektów, które zapewniają specjalne funkcje, które mogą pomóc w zwiększeniu wydajności aplikacji. Przykłady obiektów Freezable obejmują pędzle, pióra, przekształcenia, geometrie i animacje.

Co to jest Freezable?

A Freezable jest specjalnym typem obiektu, który ma dwa stany: Niezamrożone i zamrożone. Gdy nie zamrożone, Freezable wydaje się, że zachowuje się tak jak każdy inny obiekt. Po zamrożoniu Freezable nie można już modyfikować.

A Freezable zawiera Changed zdarzenie, aby powiadomić obserwatorów o wszelkich modyfikacjach obiektu. Zamrażanie a Freezable może poprawić wydajność, ponieważ nie musi już poświęcać zasobów na powiadomienia o zmianach. Zamrożone Freezable może być również współużytkowane przez wątki, podczas gdy Freezable nie można zablokować.

Chociaż Freezable Klasa ma wiele aplikacji, większość Freezable obiektów w Windows Presentation Foundation (WPF) jest związanych z podsystemem graficznym.

FreezableKlasa ułatwia korzystanie z pewnych obiektów systemu grafiki i pozwala zwiększyć wydajność aplikacji. Przykłady typów, które dziedziczą z Freezable Brush , obejmują Transform klasy, i Geometry . Ponieważ zawierają one niezarządzane zasoby, system musi monitorować te obiekty do modyfikacji, a następnie aktualizować odpowiednie zasoby niezarządzane w przypadku zmiany oryginalnego obiektu. Nawet jeśli nie modyfikujesz obiektu systemowego Graphics, system musi nadal spędzać niektóre z zasobów monitorujących obiekt, w przypadku jego zmiany.

Załóżmy na przykład, że tworzysz SolidColorBrush pędzel i używasz go do rysowania tła przycisku.

Button myButton = new Button();
SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);
myButton.Background = myBrush;
Dim myButton As New Button()
Dim myBrush As New SolidColorBrush(Colors.Yellow)
myButton.Background = myBrush

Gdy przycisk jest renderowany, WPF podsystem graficzny używa dostarczonych informacji do malowania grupy pikseli w celu utworzenia wyglądu przycisku. Mimo że używasz pełnego pędzla kolorów do opisywania, w jaki sposób przycisk powinien być namalowany, Pędzel pełnego koloru nie jest w rzeczywistości używany do malowania. System grafiki generuje szybkie i niskiego poziomu obiekty dla przycisku i pędzla. są to obiekty, które faktycznie pojawiają się na ekranie.

W przypadku zmodyfikowania pędzla należy ponownie wygenerować te obiekty niskiego poziomu. Klasa Freezable to co daje pędzlowi możliwość znalezienia odpowiednich, wygenerowanych obiektów niskiego poziomu i zaktualizowania ich w momencie zmiany. Gdy ta możliwość jest włączona, Pędzel jest określany jako "Niezamrożone".

FreezeMetoda Freezable umożliwia wyłączenie tej możliwości samoaktualizacji. Możesz użyć tej metody, aby pędzel stał się "zablokowany" lub nie można go modyfikować.

Uwaga

Nie każdy obiekt Freezable można zablokować. Aby uniknąć zgłaszania InvalidOperationException , sprawdź wartość właściwości obiektu Freezable, CanFreeze Aby ustalić, czy można ją zamrozić przed próbą jej wstrzymania.

if (myBrush.CanFreeze)
{
    // Makes the brush unmodifiable.
    myBrush.Freeze();
}
If myBrush.CanFreeze Then
    ' Makes the brush unmodifiable.
    myBrush.Freeze()
End If

Gdy nie musisz już modyfikować Freezable, zamrażanie zapewnia korzyści z wydajności. W przypadku zablokowania pędzla w tym przykładzie system grafiki nie musi już monitorować go pod kątem zmian. System grafiki może również wykonywać inne optymalizacje, ponieważ wie, że pędzel nie ulegnie zmianie.

Uwaga

Dla wygody Obiekty Freezable pozostają Niezamrożone, chyba że zostaną jawnie zablokowane.

Korzystanie z obiektów Freezable platformie

Użycie niezablokowanego Freezable przypomina użycie dowolnego innego typu obiektu. W poniższym przykładzie kolor SolidColorBrush obiektu jest zmieniany z żółtego na czerwony, gdy jest używany do rysowania tła przycisku. System grafiki działa w tle, aby automatycznie zmienić przycisk z żółtego na czerwony, przy następnym odświeżeniu ekranu.

Button myButton = new Button();
SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);
myButton.Background = myBrush;

// Changes the button's background to red.
myBrush.Color = Colors.Red;
Dim myButton As New Button()
Dim myBrush As New SolidColorBrush(Colors.Yellow)
myButton.Background = myBrush


' Changes the button's background to red.
myBrush.Color = Colors.Red

Zamrażanie elementu Freezable

Aby nie Freezable modyfikować, należy wywołać Freeze metodę. Po zablokowaniu obiektu, który zawiera obiekty Freezable, te obiekty również są zamrożone. Na przykład w przypadku zablokowania PathGeometry , cyfry i segmenty, które zawiera, byłyby zablokowane.

Nie można zamrozić elementu Freezable, jeśli którykolwiek z następujących warunków jest spełniony:

  • Ma właściwości animowane lub powiązane z danymi.

  • Ma właściwości ustawione przez zasób dynamiczny. (Zobacz zasoby XAML , aby uzyskać więcej informacji na temat zasobów dynamicznych).

  • Zawiera Freezable obiekty podrzędne, które nie mogą być zamrożone.

Jeśli te warunki mają wartość FAŁSZ i nie zamierzasz modyfikować, należy Freezable zamrozić go, aby uzyskać korzyści wynikające z wydajności opisane wcześniej.

Po wywołaniu Freeze metody Freezable nie można już jej modyfikować. Próba modyfikacji zamrożonego obiektu powoduje, że InvalidOperationException zostanie zgłoszony. Poniższy kod zgłasza wyjątek, ponieważ próbujemy zmodyfikować pędzel po jego zamrożoniu.


Button myButton = new Button();
SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);

if (myBrush.CanFreeze)
{
    // Makes the brush unmodifiable.
    myBrush.Freeze();
}

myButton.Background = myBrush;

try {

    // Throws an InvalidOperationException, because the brush is frozen.
    myBrush.Color = Colors.Red;
}catch(InvalidOperationException ex)
{
    MessageBox.Show("Invalid operation: " + ex.ToString());
}


Dim myButton As New Button()
Dim myBrush As New SolidColorBrush(Colors.Yellow)

If myBrush.CanFreeze Then
    ' Makes the brush unmodifiable.
    myBrush.Freeze()
End If

myButton.Background = myBrush

Try

    ' Throws an InvalidOperationException, because the brush is frozen.
    myBrush.Color = Colors.Red
Catch ex As InvalidOperationException
    MessageBox.Show("Invalid operation: " & ex.ToString())
End Try

Aby uniknąć zgłaszania tego wyjątku, można użyć IsFrozen metody, aby określić, czy Freezable jest zablokowany.


Button myButton = new Button();
SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);

if (myBrush.CanFreeze)
{
    // Makes the brush unmodifiable.
    myBrush.Freeze();
}

myButton.Background = myBrush;

if (myBrush.IsFrozen) // Evaluates to true.
{
    // If the brush is frozen, create a clone and
    // modify the clone.
    SolidColorBrush myBrushClone = myBrush.Clone();
    myBrushClone.Color = Colors.Red;
    myButton.Background = myBrushClone;
}
else
{
    // If the brush is not frozen,
    // it can be modified directly.
    myBrush.Color = Colors.Red;
}


Dim myButton As New Button()
Dim myBrush As New SolidColorBrush(Colors.Yellow)

If myBrush.CanFreeze Then
    ' Makes the brush unmodifiable.
    myBrush.Freeze()
End If

myButton.Background = myBrush


If myBrush.IsFrozen Then ' Evaluates to true.
    ' If the brush is frozen, create a clone and
    ' modify the clone.
    Dim myBrushClone As SolidColorBrush = myBrush.Clone()
    myBrushClone.Color = Colors.Red
    myButton.Background = myBrushClone
Else
    ' If the brush is not frozen,
    ' it can be modified directly.
    myBrush.Color = Colors.Red
End If


W poprzednim przykładzie kodu, modyfikowalna kopia została wykonana z zamrożonego obiektu za pomocą Clone metody. W następnej sekcji omówiono klonowanie bardziej szczegółowo.

Uwaga

Ponieważ zamrożony Freezable nie może być animowany, system animacji automatycznie utworzy modyfikowalne klony zablokowanych Freezable obiektów podczas próby animowania ich przy użyciu Storyboard . Aby wyeliminować narzuty wydajności wynikające z klonowania, pozostaw obiekt niezamrożony, jeśli zamierzasz go animować. Aby uzyskać więcej informacji na temat animacji przy użyciu scenorysów, zobacz Omówienie scenorysów.

Zamrażanie z adjustacji

Aby zablokować Freezable obiekt zadeklarowany w znacznikach, należy użyć PresentationOptions:Freeze atrybutu. W poniższym przykładzie SolidColorBrush jest zadeklarowana jako zasób strony i zamrożona. Jest on następnie używany do ustawiania tła przycisku.

<Page 
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options" 
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  mc:Ignorable="PresentationOptions">

  <Page.Resources>

    <!-- This resource is frozen. -->
    <SolidColorBrush 
      x:Key="MyBrush"
      PresentationOptions:Freeze="True" 
      Color="Red" />
  </Page.Resources>


  <StackPanel>

    <Button Content="A Button" 
      Background="{StaticResource MyBrush}">
    </Button>

  </StackPanel>
</Page>

Aby użyć Freeze atrybutu, należy zmapować do obszaru nazw opcji prezentacji: http://schemas.microsoft.com/winfx/2006/xaml/presentation/options . PresentationOptions jest zalecanym prefiksem do mapowania tej przestrzeni nazw:

xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options"

Ponieważ nie wszyscy czytelnicy XAML rozpoznają ten atrybut, zaleca się użycie atrybutu MC: , który można zignorować, aby oznaczyć Presentation:Freeze atrybut jako ignorowany:

xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="PresentationOptions"

Aby uzyskać więcej informacji, zobacz stronę z atrybutem MC: ignorowany .

"Odmrożenie" a Freezable

Po zamrożoniu Freezable nie można nigdy modyfikować ani odmrozić. można jednak utworzyć niezablokowany klon przy użyciu Clone CloneCurrentValue metody lub.

W poniższym przykładzie tło przycisku jest ustawione przy użyciu pędzla, a następnie Pędzel jest zablokowany. Niezablokowana kopia pędzla przy użyciu Clone metody. Klon jest modyfikowany i używany do zmiany tła przycisku z żółtego na czerwony.

Button myButton = new Button();
SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);

// Freezing a Freezable before it provides
// performance improvements if you don't
// intend on modifying it.
if (myBrush.CanFreeze)
{
    // Makes the brush unmodifiable.
    myBrush.Freeze();
}

myButton.Background = myBrush;

// If you need to modify a frozen brush,
// the Clone method can be used to
// create a modifiable copy.
SolidColorBrush myBrushClone = myBrush.Clone();

// Changing myBrushClone does not change
// the color of myButton, because its
// background is still set by myBrush.
myBrushClone.Color = Colors.Red;

// Replacing myBrush with myBrushClone
// makes the button change to red.
myButton.Background = myBrushClone;
Dim myButton As New Button()
Dim myBrush As New SolidColorBrush(Colors.Yellow)

' Freezing a Freezable before it provides
' performance improvements if you don't
' intend on modifying it. 
If myBrush.CanFreeze Then
    ' Makes the brush unmodifiable.
    myBrush.Freeze()
End If


myButton.Background = myBrush

' If you need to modify a frozen brush,
' the Clone method can be used to
' create a modifiable copy.
Dim myBrushClone As SolidColorBrush = myBrush.Clone()

' Changing myBrushClone does not change
' the color of myButton, because its
' background is still set by myBrush.
myBrushClone.Color = Colors.Red

' Replacing myBrush with myBrushClone
' makes the button change to red.
myButton.Background = myBrushClone

Uwaga

Niezależnie od używanej metody klonowania animacje nigdy nie są kopiowane do nowego Freezable .

CloneMetody i CloneCurrentValue wytwarzają głębokie kopie Freezable. Jeśli Freezable zawiera inne zamrożone Obiekty Freezable, są one również klonowane i modyfikowane. Na przykład w przypadku klonowania zamrożonego PathGeometry w celu zmodyfikowania tego elementu dane i segmenty, które zawiera, są również kopiowane i modyfikowane.

Tworzenie własnej klasy Freezable

Klasa, która powodzi się od Freezable , uzyskuje następujące funkcje.

  • Specjalne Stany: tylko do odczytu (zamrożony) i zapisywalny.

  • Bezpieczeństwo wątków: zamrożone Freezable mogą być współużytkowane przez wątki.

  • Szczegółowe powiadomienie o zmianie: w przeciwieństwie do innych DependencyObject , Obiekty Freezable zapewniają powiadomienia o zmianach w przypadku zmiany wartości właściwości podrzędnych.

  • Łatwe Klonowanie: Klasa Freezable już wdrożyła kilka metod, które tworzą głębokie klony.

A Freezable jest typem DependencyObject , i w związku z tym używa systemu właściwości zależności. Właściwości klasy nie muszą być właściwościami zależności, ale użycie właściwości zależności spowoduje zmniejszenie ilości kodu, który trzeba napisać, ponieważ Freezable Klasa została zaprojektowana z uwzględnieniem właściwości zależności. Aby uzyskać więcej informacji na temat systemu właściwości zależności, zobacz Omówienie właściwości zależności.

Każda Freezable podklasa musi zastąpić CreateInstanceCore metodę. Jeśli Klasa używa właściwości zależności dla wszystkich danych, zostanie zakończona.

Jeśli Klasa zawiera elementy członkowskie danych niezależności, należy również zastąpić następujące metody:

Należy również przestrzegać następujących reguł dostępu i zapisu do elementów członkowskich danych, które nie są właściwościami zależności:

  • Na początku dowolnego interfejsu API, który odczytuje elementy członkowskie danych niezależności, wywołaj ReadPreamble metodę.

  • Na początku dowolnego interfejsu API, który zapisuje elementy członkowskie danych właściwości niezależności, wywołaj WritePreamble metodę. (Po wywołaniu WritePreamble w interfejsie API nie trzeba wykonywać dodatkowych wywołań w ReadPreamble przypadku odczytywania także elementów członkowskich danych niezależności).

  • Wywołaj WritePostscript metodę przed wyjściem z metod, które zapisują do elementów członkowskich danych niezależnych.

Jeśli Klasa zawiera niezależne składowe danych, które są DependencyObject obiektami, należy również wywołać OnFreezablePropertyChanged metodę za każdym razem, gdy zmieniasz jedną z jej wartości, nawet jeśli tworzysz element członkowski null .

Uwaga

Bardzo ważne jest, aby rozpocząć każdą Freezable metodę przesłonięcia z wywołaniem podstawowej implementacji.

Przykład Freezable klasy niestandardowej można znaleźć w przykładowej animacji niestandardowej.

Zobacz też