Freigeben über


Übersicht über Freezable-Objekte

In diesem Thema wird beschrieben, wie Sie Freezable Objekte effektiv verwenden und erstellen, die spezielle Features bereitstellen, die zur Verbesserung der Anwendungsleistung beitragen können. Beispiele für einfrierbare Objekte sind Pinsel, Stifte, Transformationen, Geometrien und Animationen.

Was ist ein Gefrierfähiges Objekt?

Ein Freezable ist ein spezieller Objekttyp, der zwei Zustände aufweist: "Unfrozen" und "frozen". Wenn sie nicht eingefrozen, verhält sich ein Freezable wie jedes andere Objekt. Wenn eingefroren, kann eine Freezable nicht mehr geändert werden.

Ein Freezable bietet ein Ereignis Changed, um Beobachter über Änderungen am Objekt zu informieren. Das Einfrieren eines Freezable kann seine Leistung verbessern, da es keine Ressourcen mehr für das Versenden von Änderungsbenachrichtigungen aufwenden muss. Ein eingefrorenes Freezable kann auch über Threads hinweg geteilt werden, während ein nicht eingefrorenes Freezable dies nicht kann.

Obwohl die Freezable Klasse viele Anwendungen aufweist, beziehen sich die meisten Freezable Objekte in Windows Presentation Foundation (WPF) auf das Grafikuntersystem.

Die Freezable Klasse erleichtert die Verwendung bestimmter Grafiksystemobjekte und kann die Anwendungsleistung verbessern. Beispiele für Typen, die von Freezable erben, sind die klassen Brush, Transformund Geometry. Da sie nicht verwaltete Ressourcen enthalten, muss das System diese Objekte auf Änderungen überwachen und dann die entsprechenden nicht verwalteten Ressourcen aktualisieren, wenn eine Änderung am ursprünglichen Objekt vorhanden ist. Selbst wenn Sie ein Grafiksystemobjekt nicht tatsächlich ändern, muss das System dennoch einige seiner Ressourcen für die Überwachung des Objekts ausgeben, falls Sie es ändern.

Angenommen, Sie erstellen einen SolidColorBrush-Pinsel und verwenden ihn, um den Hintergrund einer Schaltfläche zu malen.

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

Wenn die Schaltfläche gerendert wird, verwendet das WPF-Grafik-Untersystem die von Ihnen bereitgestellten Informationen, um eine Gruppe von Pixeln zu zeichnen und so die Darstellung einer Schaltfläche zu erstellen. Obwohl Sie einen Pinsel mit Volltonfarbe verwendet haben, um zu beschreiben, wie die Schaltfläche gezeichnet werden soll, führt Ihr Volltonfarbpinsel das Malen nicht aus. Das Grafiksystem generiert schnelle Objekte auf niedriger Ebene für die Schaltfläche und den Pinsel, und es handelt sich um die Objekte, die tatsächlich auf dem Bildschirm angezeigt werden.

Wenn Sie den Pinsel ändern würden, müssten diese Objekte auf niedriger Ebene neu generiert werden. Die Freezable-Klasse verleiht einem Pinsel die Fähigkeit, seine entsprechenden generierten, niedrigstufigen Objekte zu finden und sie zu aktualisieren, wenn sie sich ändert. Wenn diese Funktion aktiviert ist, wird der Pinsel als "unfrozen" bezeichnet.

Mit der Freeze-Methode von Freezable können Sie diese Selbstaktualisierungsmöglichkeit deaktivieren. Mit dieser Methode können Sie den Pinsel "eingefroren" und damit unveränderlich machen.

Anmerkung

Nicht jedes einfrierbare Objekt kann eingefroren werden. Um zu vermeiden, dass ein InvalidOperationExceptionausgelöst wird, überprüfen Sie den Wert der CanFreeze-Eigenschaft des Freezable-Objekts, um festzustellen, ob es eingefroren werden kann, bevor Sie versuchen, es zu einfrieren.

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

Wenn Sie ein Freezable-Objekt nicht mehr ändern müssen, bietet das Einfrieren Leistungsvorteile. Wenn Sie den Pinsel in diesem Beispiel einfrieren würden, müsste das Grafiksystem ihn nicht mehr auf Änderungen überwachen. Das Grafiksystem kann auch andere Optimierungen vornehmen, da er weiß, dass sich der Pinsel nicht ändert.

Anmerkung

Aus Komfortgründen bleiben einfrierbare Objekte ungefroren, es sei denn, Sie frieren sie explizit ein.

Verwenden von Freezables

Die Verwendung eines nicht eingefrorenen Freezable-Objekts ist genauso wie bei jedem anderen Objekttyp. Im folgenden Beispiel ändert sich die Farbe eines SolidColorBrush von Gelb zu Rot, nachdem er zum Färben des Hintergrunds einer Schaltfläche verwendet wurde. Das Grafiksystem arbeitet hinter den Kulissen, um die Schaltfläche bei der nächsten Aktualisierung des Bildschirms automatisch von Gelb in Rot zu ändern.

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

Einfrieren eines Einfrierbaren

Um ein Freezable unveränderlich zu machen, müssen Sie die Freeze-Methode aufrufen. Wenn Sie ein Objekt einfrieren, das einfrierbare Objekte enthält, werden diese Objekte ebenfalls eingefroren. Wenn Sie z. B. eine PathGeometryeinfrieren, werden die darin enthaltenen Zahlen und Segmente ebenfalls eingefroren.

Eine Freezable Kann nicht eingefroren werden, wenn eine der folgenden Bedingungen zutrifft:

  • Es verfügt über animierte oder datengebundene Eigenschaften.

  • Es verfügt über Eigenschaften, die von einer dynamischen Ressource festgelegt wurden. (Weitere Informationen zu dynamischen Ressourcen finden Sie unter XAML-Ressourcen.)

  • Sie enthält Freezable Unterobjekte, die nicht eingefroren werden können.

Wenn diese Bedingungen nicht erfüllt sind und Sie nicht beabsichtigen, den Freezablezu ändern, sollten Sie ihn einfrieren, um die zuvor beschriebenen Leistungsvorteile zu erhalten.

Nachdem Sie die Freeze Methode einer freezable aufgerufen haben, kann sie nicht mehr geändert werden. Beim Versuch, ein fixiertes Objekt zu ändern, wird ein InvalidOperationException ausgelöst. Der folgende Code löst eine Ausnahme aus, da wir versuchen, den Pinsel zu ändern, nachdem er eingefroren wurde.


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

Um das Auslösen dieser Ausnahme zu vermeiden, können Sie die IsFrozen-Methode verwenden, um zu bestimmen, ob ein Freezable eingefroren ist.


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


Im vorherigen Codebeispiel wurde mithilfe der Clone-Methode eine modifizierbare Kopie eines fixierten Objekts erstellt. Im nächsten Abschnitt wird das Klonen ausführlicher erläutert.

Anmerkung

Da ein eingefrorenes einfrierbares Objekt nicht animiert werden kann, erstellt das Animationssystem automatisch modifizierbare Klone von eingefrorenen Freezable Objekten, wenn Sie versuchen, sie mithilfe eines Storyboardzu animieren. Um den durch Klonen verursachten Leistungsaufwand zu vermeiden, lassen Sie ein Objekt un eingefroren, wenn Sie es animieren möchten. Weitere Informationen zum Animieren mit Storyboards finden Sie in der Storyboards Overview.

Einfrieren aus Markup

Um ein im Markup deklariertes Freezable-Objekt einzufrieren, verwenden Sie das Attribut PresentationOptions:Freeze. Im folgenden Beispiel wird ein SolidColorBrush als Seitenressource deklariert und eingefroren. Es wird dann verwendet, um den Hintergrund einer Schaltfläche festzulegen.

<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>

Um das attribut Freeze zu verwenden, müssen Sie dem Namespace der Präsentationsoptionen zuordnen: http://schemas.microsoft.com/winfx/2006/xaml/presentation/options. PresentationOptions ist das empfohlene Präfix für die Abbildung dieses Namespaces.

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

Da nicht alle XAML-Leser dieses Attribut erkennen, empfiehlt es sich, das mc:Ignorable-Attribut zu verwenden, um das attribut PresentationOptions:Freeze als ignorable zu kennzeichnen:

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

Weitere Informationen finden Sie auf der Seite mc:Ignorable Attribute.

"Auftauen eines Einfrierbaren"

Sobald eine Freezable eingefroren ist, kann sie nie wieder geändert oder aufgetaut werden; Sie können jedoch einen nicht eingefrorenen Klon mithilfe der Clone- oder CloneCurrentValue-Methode erstellen.

Im folgenden Beispiel wird der Hintergrund der Schaltfläche mit einem Brush-Objekt gesetzt, und dieses Brush-Objekt wird dann fixiert. Mit der Clone-Methode wird eine nicht eingefrorene Kopie des Pinsels erstellt. Der Klon wird geändert und verwendet, um den Hintergrund der Schaltfläche von Gelb in Rot zu ändern.

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

Anmerkung

Unabhängig davon, welche Klonmethode Sie verwenden, werden Animationen nie in die neue Freezablekopiert.

Die Clone- und CloneCurrentValue-Methoden erzeugen tiefe Kopien des Freezable. Wenn das einfrierbare Objekt andere gefrostete einfrierbare Objekte enthält, werden diese ebenfalls geklont und änderbar gemacht. Wenn Sie beispielsweise eine eingefrorene PathGeometry klonen, um sie modifizierbar zu machen, werden die darin enthaltenen Zahlen und Segmente ebenfalls kopiert und modifizierbar gemacht.

Erstellen Einer eigenen einfrierbaren Klasse

Eine Klasse, die von Freezable abgeleitet wird, erhält die folgenden Features.

  • Spezielle Zustände: nur-lese (eingefroren) und schreibbarer Zustände.

  • Threadsicherheit: Ein eingefrorenes Freezable kann über Threads hinweg geteilt werden.

  • Detaillierte Änderungsbenachrichtigung: Im Gegensatz zu anderen DependencyObjectliefern Freezable-Objekte Änderungsbenachrichtigungen, wenn sich die Werte von Untereigenschaften ändern.

  • Einfaches Klonen: Die Freezable-Klasse hat bereits mehrere Methoden implementiert, die tiefe Klonen erzeugen.

Ein Freezable ist eine Art von DependencyObjectund benutzt daher das System der Abhängigkeitseigenschaften. Ihre Klasseneigenschaften müssen nicht Abhängigkeitseigenschaften sein, aber die Verwendung von Abhängigkeitseigenschaften verringert die Menge des zu schreibenden Codes, da die Freezable Klasse unter Berücksichtigung von Abhängigkeitseigenschaften entworfen wurde. Weitere Informationen zum System der Abhängigkeitseigenschaften finden Sie in der Abhängigkeitseigenschaften-Übersicht.

Jede Freezable-Unterklasse muss die CreateInstanceCore-Methode überschreiben. Wenn Ihre Klasse Abhängigkeitseigenschaften für alle Daten verwendet, sind Sie fertig.

Wenn Ihre Klasse Nicht-Abhängigkeitseigenschaftsdatenmmber enthält, müssen Sie auch die folgenden Methoden außer Kraft setzen:

Außerdem müssen Sie die folgenden Regeln für den Zugriff und das Schreiben auf Datenmber beachten, die keine Abhängigkeitseigenschaften sind:

  • Rufen Sie am Anfang jeder API, die Nicht-Abhängigkeitseigenschaftsdatenmitglieder liest, die ReadPreamble-Methode auf.

  • Rufen Sie zu Beginn einer beliebigen API, die Datenmitglieder ohne Abhängigkeitseigenschaften schreibt, die WritePreamble-Methode auf. (Nachdem Sie WritePreamble in einer API aufgerufen haben, müssen Sie keinen zusätzlichen Aufruf an ReadPreamble vornehmen, wenn Sie auch Nicht-Abhängigkeitseigenschaftsdatenelemente lesen.)

  • Rufen Sie die WritePostscript-Methode auf, bevor Sie Methoden verlassen, die in Nicht-Abhängigkeitseigenschaftsdatenmitglieder schreiben.

Wenn Ihre Klasse Nicht-Abhängigkeitseigenschafts-Datenelemente enthält, die DependencyObject-Objekte sind, müssen Sie die OnFreezablePropertyChanged-Methode auch jedes Mal aufrufen, wenn Sie einen ihrer Werte ändern, selbst wenn Sie das Datenelement auf nullfestlegen.

Anmerkung

Es ist sehr wichtig, dass Sie jede Methode Freezable, die Sie überschreiben, mit einem Aufruf der Basisimplementierung beginnen.

Ein Beispiel für eine benutzerdefinierte Klasse vom Typ Freezable finden Sie im Beispiel für benutzerdefinierte Animation .

Siehe auch