Översikt över freezable-objekt

Det här avsnittet beskriver hur du effektivt använder och skapar Freezable objekt, som tillhandahåller särskilda funktioner som kan hjälpa till att förbättra programmets prestanda. Exempel på frystbara objekt är penslar, pennor, transformationer, geometrier och animationer.

Vad är en frysbar?

En Freezable är en särskild typ av objekt som har två tillstånd: avfryst och frusen. När den avfrostas verkar en Freezable bete sig som alla andra objekt. När den är frusen kan en Freezable inte längre ändras.

En Freezable tillhandahåller en Changed-händelse för att informera observatörer om eventuella ändringar av objektet. Att frysa en Freezable kan förbättra dess prestanda eftersom den inte längre behöver spendera resurser på ändringsmeddelanden. En frusen Freezable kan också delas mellan trådar, medan en ofrozen Freezable inte kan.

Freezable Även om klassen har många program är de flesta Freezable objekt i Windows Presentation Foundation (WPF) relaterade till grafikundersystemet.

Klassen Freezable gör det enklare att använda vissa grafiksystemobjekt och kan förbättra programmets prestanda. Exempel på typer som ärver från Freezable inkluderar klasserna Brush, Transformoch Geometry . Eftersom de innehåller ohanterade resurser måste systemet övervaka dessa objekt för ändringar och sedan uppdatera motsvarande ohanterade resurser när det ursprungliga objektet ändras. Även om du inte ändrar ett grafiksystemobjekt måste systemet fortfarande spendera en del av sina resurser på att övervaka objektet, om du ändrar det.

Anta till exempel att du skapar en SolidColorBrush pensel och använder den för att måla bakgrunden till en knapp.

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

När knappen återges använder WPF-grafikundersystemet den information du angav för att måla en grupp bildpunkter för att skapa utseendet på en knapp. Även om du använde en helfärgsborste för att beskriva hur knappen ska målas, utför din helfärgsborste faktiskt inte målningen. Grafiksystemet genererar snabba objekt på låg nivå för knappen och penseln, och det är de objekt som faktiskt visas på skärmen.

Om du skulle ändra penseln måste dessa lågnivåobjekt återskapas. Den frysbara klassen är det som ger en pensel möjlighet att hitta sina motsvarande genererade objekt på låg nivå och uppdatera dem när penseln ändras. När den här möjligheten är aktiverad sägs penseln vara "ofryst".

Med en freezable-metod Freeze kan du inaktivera den här självuppdateringsförmågan. Du kan använda den här metoden för att göra penseln "frusen" eller omodifierbar.

Anmärkning

Alla freezable-objekt kan inte frysas. Om du vill undvika att utlösa en InvalidOperationException, kontrollera värdet för Freezable-objektets CanFreeze egenskap för att avgöra om det kan frysas innan du försöker frysa det.

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

När du inte längre behöver ändra en frysbar, ger frysning av den prestandafördelar. Om du skulle frysa penseln i det här exemplet skulle grafiksystemet inte längre behöva övervaka den för ändringar. Grafiksystemet kan också göra andra optimeringar eftersom det vet att penseln inte ändras.

Anmärkning

För enkelhetens skull förblir frysbara objekt oförändrade om du inte uttryckligen fryser dem.

Använda frysbara objekt

Att använda en ofryst frystbar objekt är som att använda vilken annan typ av objekt som helst. I följande exempel ändras färgen på en SolidColorBrush från gul till röd när den används för att måla bakgrunden till en knapp. Grafiksystemet fungerar i bakgrunden för att automatiskt ändra knappen från gult till rött nästa gång skärmen uppdateras.

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

Frysning av en frysbar

Om du vill göra en Freezable omodifierbar, anropar du dess Freeze-metod. När du fryser ett objekt som innehåller frysbara objekt fryses även dessa objekt. Om du till exempel fryser en PathGeometry, skulle de siffror och segment som den innehåller också frysas.

En Freezable kan inte frysas om något av följande är sant:

  • Den har animerade egenskaper eller databundna egenskaper.

  • Den har egenskaper som anges av en dynamisk resurs. (Mer information om dynamiska resurser finns i XAML-resurser .)

  • Den innehåller Freezable underobjekt som inte kan frysas.

Om dessa villkor är falska och du inte tänker ändra Freezable, bör du låsa det för att få de prestandafördelar som beskrevs tidigare.

När du anropar metoden freezable Freeze kan den inte längre ändras. Om du försöker ändra ett fruset objekt genereras ett InvalidOperationException . Följande kod genererar ett undantag eftersom vi försöker ändra penseln när den har frusits.


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

Om du vill undvika att utlösa det här undantaget kan du använda IsFrozen metoden för att avgöra om en Freezable är låst.


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


I föregående kodexempel gjordes en ändringsbar kopia av ett fruset Clone objekt med metoden . I nästa avsnitt beskrivs kloning mer detaljerat.

Anmärkning

Eftersom en frysbar som är fryst inte kan animeras kommer animeringssystemet automatiskt att skapa kloner som kan modifieras av Freezable objekt som är frysta när du försöker animera dem med en Storyboard. Om du vill eliminera prestandakostnaderna som orsakas av kloning lämnar du ett objekt ofryst om du tänker animera det. Mer information om hur du animerar med storyboards finns i Översikt över Storyboards.

Frysning från markering

För att frysa ett Freezable objekt som deklarerats i markering använder du attributet PresentationOptions:Freeze. I följande exempel deklareras en SolidColorBrush som en sidresurs och fryses. Den används sedan för att ange bakgrunden till en knapp.

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

Om du vill använda Freeze attributet måste du mappa till namnområdet presentationsalternativ: http://schemas.microsoft.com/winfx/2006/xaml/presentation/options. PresentationOptions är det rekommenderade prefixet för att mappa det här namnområdet:

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

Eftersom inte alla XAML-läsare känner igen det här attributet rekommenderar vi att du använder attributet mc:Ignorable för att markera PresentationOptions:Freeze attributet som okunnigt:

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

Mer information finns på sidan mc:Ignorable Attribute.

Upptining av ett nedfryst objekt

När en Freezable har frusits kan den aldrig ändras eller avfrysas; du kan dock skapa en ofrusen klon med hjälp av Clone eller CloneCurrentValue metod.

I följande exempel anges knappens bakgrund med en pensel och borsten fryses sedan. En ofryst kopia görs av penseln med hjälp av Clone metoden. Klonen modifieras och används för att ändra bakgrunden på knappen från gul till röd.

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

Anmärkning

Oavsett vilken klonmetod du använder kopieras aldrig animeringar till den nya Freezable.

Metoderna Clone och CloneCurrentValue producerar djupa kopior av det frysbara. Om den frysbara innehåller andra frysta frysbara objekt klonas de också och görs modifierbara. Om du till exempel klonar en frusen PathGeometry för att göra den ändringsbar kopieras även de siffror och segment som den innehåller och görs modifierbara.

Skapa din egen frysbara klass

En klass som härleds från Freezable får följande funktioner.

  • Särskilda tillstånd: skrivskyddat (fruset) och skrivbart tillstånd.

  • Trådsäkerhet: en frusen Freezable kan delas mellan olika trådar.

  • Detaljerad ändringsmeddelande: Till skillnad från andra DependencyObjectobjekt ger Freezable-objekt ändringsmeddelanden när underegenskapsvärden ändras.

  • Enkel kloning: Klassen Freezable har redan implementerat flera metoder som producerar djupa kloner.

A Freezable är en typ av DependencyObjectoch använder därför beroendeegenskapssystemet. Klassegenskaperna behöver inte vara beroendeegenskaper, men om du använder beroendeegenskaper minskas mängden kod som du måste skriva eftersom Freezable klassen har utformats med beroendeegenskaper i åtanke. Mer information om beroendeegenskapssystemet finns i Översikt över beroendeegenskaper.

Varje Freezable underklass måste åsidosätta CreateInstanceCore metoden. Om klassen använder beroendeegenskaper för alla sina data är du klar.

Om klassen innehåller icke-beroende egenskapsdatamedlemmar måste du också åsidosätta följande metoder:

Du måste också följa följande regler för åtkomst till och skrivning till datamedlemmar som inte är beroendeegenskaper:

  • I början av varje API som läser datamedlemmar av icke-beroende egenskaper, anropa metoden ReadPreamble.

  • I början av ett API som skriver icke-beroende egenskapsdatamedlemmar anropar WritePreamble du metoden. (När du har anropat WritePreamble i ett API behöver du inte göra ytterligare ett anrop till ReadPreamble om du också läser icke-beroende egenskapsdatamedlemmar.)

  • WritePostscript Anropa metoden innan du avslutar metoder som skriver till icke-beroende egenskapsdatamedlemmar.

Om klassen innehåller icke-beroendeegenskapsdatamedlemmar som är DependencyObject objekt, måste du också anropa OnFreezablePropertyChanged metoden varje gång du ändrar ett av deras värden, även om du ställer in medlemmen på null.

Anmärkning

Det är mycket viktigt att du börjar varje Freezable metod som du åsidosätter med ett anrop till basimplementeringen.

Ett exempel på en anpassad Freezable klass finns i Exempel på anpassad animering.

Se även