Compartilhar via


Visão geral sobre objetos Freezable

Este tópico descreve como usar com eficiência e criar objetos Freezable, que oferecem recursos especiais que podem ajudar a melhorar o desempenho do aplicativo. Exemplos de objetos Freezable incluem pincéis, canetas, transformações, geometrias e animações.

Este tópico contém as seções a seguir:

O que é um Freezable?

A Freezable é um tipo especial de objeto que tem dois estados: descongeladas e congeladas. Quando descongelado, um Freezable parece se comportar como qualquer outro objeto. Quando congelado, um Freezable não pode mais ser modificado.

Um Freezable fornece um evento Changed para notificar observadores de quaisquer modificações do objeto. Congelar um Freezable pode melhorar seu desempenho, porque ele não precisa gastar recursos em notificações de alteração. Um Freezable congelado também pode ser compartilhado entre threads, enquanto um Freezable descongelado não pode.

Embora a classe Freezable tenha muitas aplicações, a maioria dos objetos Freezable em Windows Presentation Foundation (WPF) estão relacionados ao subsistema de elementos gráficos.

A classe Freezable facilita usar determinados elementos objetos do sistema gráfico e pode ajudar a melhorar o desempenho do aplicativo. Exemplos de tipos que herdam de Freezable incluem as classes Brush, Transform e Geometry. Porque eles contêm recursos não gerenciados, o sistema deve monitorar esses objetos para modificações e, em seguida, atualizar seus recursos não gerenciados correspondentes quando houver uma alteração no objeto original. Mesmo se você não realmente modificar um objeto do sistema de elementos gráficos, o sistema deve ainda gastar alguns dos seus recursos monitorando o objeto, para o caso de você alterá-lo.

Por exemplo, suponha que você cria um pincel SolidColorBrush e usa-o para pintar o plano de fundo de um botão.

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

Quando o botão é desenhado, o subsistema gráfico de WPF usa as informações fornecidas para pintar um grupo de pixels para criar a aparência de um botão. Embora você tenha usado um pincel de cor sólida para descrever como o botão deve ser pintado, seu pincel de cor sólida, na verdade, não faz a pintura. O sistema de elementos gráficos gera objetos rápidos, de baixo nível para o botão e o pincel, e são esses objetos que realmente aparecem na tela.

Se você fosse modificar o pincel, esses objetos de baixo nível precisariam ser gerados novamente. A classe Freezable é o que proporciona a um pincel a capacidade de localizar seus objetos de baixo nível gerados correspondentes e atualizá-los quando ele altera. Quando esse recurso é habilitado, o pincel é chamado de "descongelado."

O método Freeze de um Freezable permite que você desative essa capacidade autoatualização. Você pode usar esse método para tornar o pincel "congelado", ou não modificável.

ObservaçãoObservação:

Nem todo objeto Freezable pode ser congelado. Para evitar o lançamento de um InvalidOperationException, verifique o valor do objeto Freezable CanFreeze propriedade para determinar se pode ser congelado antes de tentar congelá-lo.

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

Quando você não precisar mais modificar um Freezable, congelá-lo fornece vantagens de desempenho. Se você fosse congelar o pincel nesse exemplo, o sistema de elementos gráficos não precisaria mais monitorá-lo para alterações. O sistema gráfico também pode fazer outras otimizações, porque ele sabe que o pincel não sofrerá alterações.

ObservaçãoObservação:

Para sua conveniência, freezable objetos permanecer não congeladas, a menos que você explicitamente congelar.

Usando Freezables

Usar um Freezable descongelado é como usar qualquer outro tipo de objeto. No exemplo a seguir, a cor de um SolidColorBrush é alterada de amarelo para vermelho depois de ele ter sido usado para pintar o plano de fundo de um botão. O sistema gráfico funciona em segundo plano para automaticamente alterar o botão de amarelo para vermelho na próxima vez em que a tela for atualizada.

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


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

Congelando uma Freezable

Para tornar um Freezable não modificável, você chama seu método Freeze. Quando você congela um objeto que contém objetos Freezable, esses objetos são congelados também. Por exemplo, se você congelasse uma PathGeometry, ilustrações e segmentos que ela contivesse seriam congelados também.

Um Freezable não pode ser congelado se alguma das seguintes for verdadeira:

  • Tem propriedades animadas ou ligadas a dados.

  • Ele possui propriedades definidas por um recurso dinâmico. (Consulte Visão geral sobre Recursos para obter mais informações sobre recursos dinâmicos).

  • Ele contém subobjetos Freezable que não podem ser congelados.

Se essas condições forem falsas, e você não pretende modificar o Freezable, então você deve congelá-lo para obter os benefícios de desempenho descritos anteriormente.

Depois de você chamar o método Freeze de um Freezable, ele não pode mais ser modificado. Tentar modificar um objeto congelado faz com que uma InvalidOperationException seja lançada. O código a seguir gera uma exceção, pois tenta-se modificar o pincel depois de ele ter sido congelado.

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());
}

Para evitar que esta exceção seja lançada, você pode usar o método IsFrozen para determinar se um Freezable está congelado.

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


No exemplo de código anterior, uma cópia modificável foi feita de um objeto congelado usando o método Clone. A próxima seção aborda clonagem em mais detalhes.

Observação Como um Freezable congelado não pode ser animado, o sistema de animação criará automaticamente clones modificáveis de objetos Freezable congelados quando você tentar animá-los com um Storyboard. Para eliminar a sobrecarga de desempenho causado pela clonagem, deixe um objeto descongelado se você pretende animá-lo. Para obter mais informações sobre animação com storyboards, consulte o Visão geral sobre Storyboards.

Freezing a partir de marcação

Para congelar um objeto Freezable declarado na marcação, você usa o atributo PresentationOptions:Freeze. No exemplo a seguir, um SolidColorBrush é declarado como um recurso de página e congelado. Em seguida, ele é usado para definir o plano de fundo de um botão.

<Page 
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:PresentationOptions="https://schemas.microsoft.com/winfx/2006/xaml/presentation/options" 
  xmlns:mc="https://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>

Para usar o Freeze atributo, você deve mapear para o namespace de opções de apresentação: https://schemas.microsoft.com/winfx/2006/xaml/presentation/options. PresentationOptions é o prefixo recomendado para mapear esse namespace:

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

Porque nem todos os leitores XAML reconhecem esse atributo, é recomendável que você use o mc:Ignorable Attribute para marcar o atributo Presentation:Freeze como ignorável:

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

Para mais informações, consulte a página mc:Ignorable Attribute.

Descongelando um Freezable

Após congelado, um Freezable nunca pode ser modificado ou descongelado; no entanto, você pode criar um clone descongelado usando os métodos Clone ou CloneCurrentValue.

No exemplo a seguir, o plano de fundo do botão é definido com um pincel e esse pincel é então congelado. Uma cópia descongelada é feita do pincel usando o método Clone. O clone é modificado e usado para alterar o plano de fundo do botão de amarelo para vermelho.

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;
ObservaçãoObservação:

Independentemente do método clone usar, animações nunca são copiadas para o novo Freezable.

Os métodos Clone e CloneCurrentValue produzem cópias profundas do Freezable. Se o Freezable contiver outros objetos Freezable congelados, eles também são clonados e tornados modificáveis. Por exemplo, se você clonar um PathGeometry congelado para torná-lo modificável, as ilustrações e os segmentos que ele contém são também copiados e tornados modificáveis.

Criando sua própria classe Freezable

Uma classe que é derivada de Freezable obtém os recursos a seguir.

  • Estados especiais: somente leitura (congeladas) e um estado gravável.

  • acesso thread-safe: um congeladas Freezable pode ser compartilhado entre segmentos.

  • Notificação de alterações detalhadas: Ao contrário de outros DependencyObjects, objetos Freezable fornecem notificações de alterar quando sub-propriedade valores de alterar.

  • Clonagem fáceis: a classe Freezable já implementou vários métodos que produzem clones profunda.

Um Freezable é um tipo de DependencyObject e, portanto, usa o sistema de propriedade de dependência. As propriedades de classe não precisam ser propriedades de dependência, mas usar propriedades de dependência reduzirá a quantidade de código que você precisa escrever, porque a classe Freezable foi desenvolvida com propriedades de dependência em mente. Para obter mais informações sobre o sistema de propriedade de dependência, consulte o Visão geral sobre propriedades de dependência.

Cada subclasse Freezable deve sobrescrever o método CreateInstanceCore. Se a classe usa as propriedades de dependência para todos os seus dados, está concluído.

Se a classe contém membros de dados de propriedades não dependentes, você também deve sobrescrever os seguintes métodos:

Você também deve observar as regras a seguir para acessar e gravar em dados membros que não são propriedades de dependência:

  • No início de qualquer API que lê membros de dados de propriedades não dependentes, chame o método ReadPreamble.

  • No início de API que escreve membros de dados de propriedades não dependentes, chame o método WritePreamble. (Depois de você ter chamado WritePreamble em uma API, você não precisa fazer uma chamada adicional a ReadPreamble se você também ler membros de dados de propriedades não dependentes.)

  • Chame o método WritePostscript antes de sair de métodos que gravam membros de dados de propriedades não dependentes.

Se a classe contém membros de dados de propriedades não dependentes que são objetos DependencyObject, você deve também chamar o método OnFreezablePropertyChanged sempre que você alterar seus valores, mesmo se você estiver configurando o membro para null.

ObservaçãoObservação:

É muito importante que você começar a cada Freezable método substituir por uma telefonar para a implementação base.

Para um exemplo de uma classe Freezable personalizada, consulte o Personalizar Animação exemplo.

Consulte também

Tarefas

Personalizar Animação exemplo

Conceitos

Visão geral sobre propriedades de dependência

Propriedades de Dependência Personalizada

Referência

Freezable