Přehled zablokovatelných objektů

Toto téma popisuje, jak efektivně používat a vytvářet Freezable objekty, které poskytují speciální funkce, které pomáhají zlepšit výkon aplikace. Mezi příklady zamrznutelných objektů patří štětce, pera, transformace, geometrie a animace.

Co je zmrazení?

A Freezable je speciální typ objektu, který má dva stavy: unfrozen a frozen. Když se zruší, zdá se, Freezable že se chová stejně jako jakýkoli jiný objekt. Když se zablokuje, Freezable už se nedá změnit.

Changed Poskytuje Freezable událost, která pozorovatelům oznámí všechny úpravy objektu. Zmrazení Freezable může zlepšit svůj výkon, protože už nemusí trávit prostředky na oznámení o změnách. Zmrazené Freezable můžou být také sdíleny mezi vlákny, zatímco unfrozen Freezable nemůže.

Freezable Ačkoli třída má mnoho aplikací, většina Freezable objektů v systému Windows Presentation Foundation (WPF) souvisí s grafickým podsystémem.

Třída Freezable usnadňuje používání určitých grafických systémových objektů a pomáhá zlepšit výkon aplikace. Příklady typů, které dědí z Freezable , zahrnují Brush, Transforma Geometry třídy. Vzhledem k tomu, že obsahují nespravované prostředky, musí systém tyto objekty monitorovat a aktualizovat odpovídající nespravované prostředky, pokud dojde ke změně původního objektu. I když ve skutečnosti neupravíte objekt grafického systému, musí systém stále trávit některé jeho prostředky monitorováním objektu, pokud ho změníte.

Předpokládejme například, že vytvoříte SolidColorBrush štětec a použijete ho k vykreslení pozadí tlačítka.

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

Když se tlačítko vykreslí, použije dílčí systém grafiky WPF informace, které jste zadali k vykreslení skupiny pixelů k vytvoření vzhledu tlačítka. I když jste použili plný barevný štětec k popisu způsobu malování tlačítka, plný barevný štětec ve skutečnosti neprovádí malování. Grafický systém generuje pro tlačítko a štětec rychlé objekty nízké úrovně a jedná se o objekty, které se skutečně zobrazují na obrazovce.

Pokud byste chtěli upravit štětec, tyto objekty nízké úrovně by se musely znovu vygenerovat. Zamrznutá třída je to, co dává štětec schopnost najít odpovídající vygenerované, nízkoúrovňové objekty a aktualizovat je při změně. Když je tato schopnost povolená, štětec se říká, že je "nefrozen".

Metoda zmrazení Freeze umožňuje zakázat tuto možnost samoobslužné aktualizace. Tuto metodu můžete použít k tomu, aby se kartáč stal "ukotveným" nebo neupravitelným.

Poznámka:

Ne každý zmrazený objekt lze zamrznout. Chcete-li zabránit vyvolání InvalidOperationException, zkontrolujte hodnotu Freezable objekt vlastnost CanFreeze určit, zda může být zmrazena před pokusem o zablokování.

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

Pokud už není nutné měnit zmrazení, poskytuje zmrazení výhody výkonu. Kdybyste v tomto příkladu zamrzli štětec, grafický systém by už ho nemusel sledovat kvůli změnám. Grafický systém může také provádět další optimalizace, protože ví, že se štětec nezmění.

Poznámka:

Pro usnadnění práce zůstanou zamrzlé objekty nezamrzlé, pokud je explicitně neumrznete.

Použití zamrznutí

Použití nezamrznutelného mrazu se podobá použití jakéhokoli jiného typu objektu. V následujícím příkladu se barva barvy SolidColorBrush tlačítka změní ze žluté na červenou. Grafický systém funguje na pozadí a automaticky změní tlačítko ze žluté na červenou při příští aktualizaci obrazovky.

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

Zmrazení zamrznutí

Chcete-li provést Freezable neupravitelné, zavoláte jeho Freeze metodu. Když ukotvit objekt, který obsahuje ukotvené objekty, jsou tyto objekty také zablokovaný. Pokud například ukotvíte PathGeometry, údaje a segmenty, které obsahuje, by se také zmrazily.

Zamrznutí nelze zamrznout, pokud platí některá z následujících skutečností:

  • Obsahuje animované vlastnosti nebo vlastnosti vázané na data.

  • Má vlastnosti nastavené dynamickým prostředkem. (Viz Zdroje XAML pro další informace o dynamických prostředcích.)

  • Obsahuje Freezable dílčí objekty, které nelze zablokovat.

Pokud jsou tyto podmínky nepravdivé a nemáte v úmyslu Freezableje upravit, měli byste ho ukotvit, abyste získali výhody výkonu popsané výše.

Jakmile zavoláte zamrznutelnou Freeze metodu, už ji nelze upravit. Pokus o úpravu ukotveného objektu způsobí InvalidOperationException vyvolání. Následující kód vyvolá výjimku, protože se pokusíme upravit štětec po zablokování.


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

Chcete-li se vyhnout vyvolání této výjimky, můžete použít metodu IsFrozenFreezable k určení, zda je zablokovaný.


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


V předchozím příkladu kódu byla modifikovatelná kopie vyrobena z ukotveného objektu Clone pomocí metody. Další část popisuje klonování podrobněji.

Poznámka:

Vzhledem k tomu, že zmrazené ukotvení nelze animovat, animační systém automaticky vytvoří modifikovatelné klony ukotvených Freezable objektů při pokusu o animaci pomocí Storyboard. Pokud chcete eliminovat režii na výkon způsobenou klonováním, ponechte objekt nerušený, pokud ho chcete animovat. Další informace o animaci pomocí scénářů najdete v přehledu scénářů.

Ukotvení z revizí

Chcete-li ukotvit Freezable objekt deklarovaný v kódu, použijte PresentationOptions:Freeze atribut. V následujícím příkladu SolidColorBrush je deklarován jako prostředek stránky a zablokovaný. Pak se použije k nastavení pozadí tlačítka.

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

Chcete-li použít Freeze atribut, musíte mapovat na obor názvů možností prezentace: http://schemas.microsoft.com/winfx/2006/xaml/presentation/options. PresentationOptions je doporučená předpona pro mapování tohoto oboru názvů:

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

Vzhledem k tomu, že tento atribut nerozpozná všichni čtenáři XAML, doporučujeme použít atribut mc:Ignorable k označení atributu PresentationOptions:Freeze jako ignorable:

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

Další informace najdete na stránce mc:Ignorable Attribute .

"Odblokování" zmrazení

Jakmile se Freezable zablokuje, nedá se nikdy změnit ani zrušit. Můžete však vytvořit klon unfrozen pomocí Clone metody nebo CloneCurrentValue metody.

V následujícím příkladu je pozadí tlačítka nastaveno štětcem a tento štětec je pak ukotvený. Nefrozen kopie je vyrobena z štětce pomocí Clone metody. Klon se upraví a použije se ke změně pozadí tlačítka ze žluté na červenou.

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

Poznámka:

Bez ohledu na to, kterou klonovací metodu používáte, animace se nikdy nekopírují do nového Freezable.

CloneCurrentValue A Clone metody vytvářejí hluboké kopie zmrazení. Pokud zmrazení obsahuje další zmrazené objekty, jsou také klonovány a upraveny. Pokud například klonujete zmrazené PathGeometry , aby bylo možné ho upravit, údaje a segmenty, které obsahuje, se také zkopírují a změní.

Vytvoření vlastní zamrznutelné třídy

Třída, která je odvozena z Freezable získání následujících funkcí.

  • Zvláštní stavy: jen pro čtení (zmrazené) a zapisovatelný stav.

  • Bezpečnost vláken: Ukotvené Freezable vlákno lze sdílet napříč vlákny.

  • Podrobné oznámení o změnách: Na rozdíl od jiných DependencyObjects, Ukotvené objekty poskytují oznámení o změnách při změně hodnot dílčí vlastnosti.

  • Snadné klonování: Zamrznutelná třída již implementovala několik metod, které vytvářejí hluboké klony.

A Freezable je typ DependencyObject, a proto používá systém vlastností závislostí. Vlastnosti třídy nemusí být vlastnosti závislostí, ale použití vlastností závislosti sníží množství kódu, který musíte napsat, protože Freezable třída byla navržena s ohledem na vlastnosti závislostí. Další informace o systému vlastností závislostí naleznete v přehledu vlastností závislostí.

Každá Freezable podtřída musí přepsat metodu CreateInstanceCore . Pokud vaše třída používá vlastnosti závislostí pro všechna její data, jste hotovi.

Pokud vaše třída obsahuje datové členy vlastností, které nejsou závislé, musíte také přepsat následující metody:

Musíte také dodržovat následující pravidla pro přístup k datovým členům, kteří nejsou vlastnostmi závislosti a zápis do nich:

  • Na začátku jakéhokoli rozhraní API, které čte členy dat vlastností, které nejsou závislé, zavolejte metodu ReadPreamble .

  • Na začátku libovolného rozhraní API, které zapisuje členy dat vlastností, které nejsou závislé, zavolejte metodu WritePreamble . (Po volání WritePreamble v rozhraní API nemusíte provádět další volání ReadPreamble , pokud také čtete datové členy vlastností, které nejsou závislé.)

  • Volejte metodu WritePostscript před ukončením metod, které zapisují do datových členů vlastností, které nejsou závislé.

Pokud vaše třída obsahuje datové členy, které nejsou závislé vlastnosti, které jsou DependencyObject objekty, musíte také volat metodu OnFreezablePropertyChanged pokaždé, když změníte jednu z jejich hodnot, i když nastavujete člena na null.

Poznámka:

Je velmi důležité, abyste zahájili každou Freezable metodu, kterou přepíšete voláním základní implementace.

Příklad vlastní Freezable třídy najdete v ukázce vlastní animace.

Viz také