Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Este tópico descreve como usar e criar objetos Freezable de forma eficaz, que fornecem recursos especiais que podem ajudar a melhorar o desempenho do aplicativo. Exemplos de objetos congeláveis incluem pincéis, canetas, transformações, geometrias e animações.
O que é um Freezable?
Um Freezable é um tipo especial de objeto que tem dois estados: descongelado e congelado. Quando descongelado, um Freezable parece comportar-se como qualquer outro objeto. Quando congelado, um Freezable não pode mais ser modificado.
Um Freezable fornece um evento Changed para notificar os observadores de quaisquer modificações no objeto. Congelar um Freezable pode melhorar seu desempenho, porque ele não precisa mais gastar recursos em notificações de alteração. Um Freezable congelado também pode ser compartilhado entre threads, enquanto um Freezable que não está congelado não pode.
Embora a classe Freezable tenha muitos aplicativos, a maioria dos objetos Freezable no Windows Presentation Foundation (WPF) estão relacionados ao subsistema gráfico.
A classe Freezable facilita o uso de determinados 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, Transforme Geometry. Como eles contêm recursos não gerenciados, o sistema deve monitorar esses objetos em busca de modificações e, em seguida, atualizar os recursos não gerenciados correspondentes quando houver uma alteração no objeto original. Mesmo que você não modifique um objeto do sistema gráfico, o sistema ainda deve gastar alguns de seus recursos monitorando o objeto, caso você o altere.
Por exemplo, suponha que você crie um pincel SolidColorBrush e use-o para pintar o plano de fundo de um botão.
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
Quando o botão é renderizado, o subsistema de gráficos 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 não faz a pintura. O sistema gráfico gera objetos rápidos e de baixo nível para o botão e o pincel, e são esses objetos que realmente aparecem na tela.
Se você modificasse o pincel, esses objetos de baixo nível teriam que ser regenerados. A classe Freezable é o que dá a um pincel a capacidade de encontrar os seus objetos correspondentes gerados e de baixo nível, e de os atualizar quando mudam. Quando esta capacidade está ativada, diz-se que a escova está "descongelada".
O método Freeze de um freezable permite desativar essa capacidade de autoatualização. Você pode usar esse método para fazer com que o pincel fique "congelado" ou não modificável.
Observação
Nem todos os objetos Freezable podem ser congelados. Para evitar lançar um InvalidOperationException, verifique o valor da propriedade CanFreeze do objeto Freezable para determinar se ele pode ser congelado antes de tentar congelá-lo.
if (myBrush.CanFreeze)
{
// Makes the brush unmodifiable.
myBrush.Freeze();
}
If myBrush.CanFreeze Then
' Makes the brush unmodifiable.
myBrush.Freeze()
End If
Quando já não precisas de modificar um objeto congelável, bloqueá-lo pode proporcionar vantagens de desempenho. Se você congelasse o pincel neste exemplo, o sistema gráfico não precisaria mais monitorá-lo em busca de alterações. O sistema gráfico também pode fazer outras otimizações, porque sabe que o pincel não vai mudar.
Observação
Por conveniência, os objetos congeláveis permanecem descongelados, a menos que você os congele explicitamente.
Usando Freezables
Usar um objeto congelável que não está congelado é como usar qualquer outro tipo de objeto. No exemplo a seguir, a cor de um SolidColorBrush é alterada de amarelo para vermelho depois de ser usada para pintar o plano de fundo de um botão. O sistema gráfico funciona nos bastidores para alterar automaticamente o botão de amarelo para vermelho na próxima vez 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;
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
Congelar algo congelável
Para tornar um Freezable inmodificável, você chama seu método Freeze. Quando você congela um objeto que contém objetos congeláveis, esses objetos também são congelados. Por exemplo, se congelar um PathGeometry, os números e segmentos que contém também serão congelados.
Um congelável não pode ser congelado se alguma das seguintes situações for verdadeira:
Tem propriedades animadas ou ligadas a dados.
Tem propriedades definidas por um recurso dinâmico. (Consulte os Recursos XAML para obter mais informações sobre recursos dinâmicos.)
Ele contém Freezable subobjetos 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 chamar o método Freeze de um freezable, ele não pode mais ser modificado. A tentativa de modificar um objeto congelado faz com que um InvalidOperationException seja lançado. O código a seguir lança uma exceção, porque tentamos modificar o pincel depois que ele foi 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());
}
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
Para evitar lançar essa exceção, 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;
}
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
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 discute a clonagem com mais detalhes.
Observação
Como um congelável 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 causada pela clonagem, deixe um objeto descongelado se você pretende animá-lo. Para obter mais informações sobre como animar com storyboards, consulte a Visão geral do Storyboards.
Congelamento a partir de marcação
Para congelar um objeto Freezable declarado na marcação, use o atributo PresentationOptions:Freeze. No exemplo a seguir, um SolidColorBrush é declarado como um recurso de página e congelado. Em seguida, é usado para definir o fundo de um botão.
<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>
Para usar o atributo Freeze, você deve mapear para o namespace de opções de apresentação: http://schemas.microsoft.com/winfx/2006/xaml/presentation/options.
PresentationOptions é o prefixo recomendado para mapear este namespace:
xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options"
Como nem todos os leitores XAML reconhecem esse atributo, é recomendável usar o mc:Ignorable Attribute para marcar o atributo PresentationOptions:Freeze como ignorable:
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="PresentationOptions"
Para obter mais informações, consulte a página mc:Ignorable Attribute.
Descongelar um Objeto Congelável
Uma vez congelado, um Freezable nunca pode ser modificado ou descongelado; no entanto, você pode criar um clone descongelado usando o método Clone ou CloneCurrentValue.
No exemplo a seguir, o plano de fundo do botão é definido com um pincel e esse pincel é congelado. Uma cópia descongelada é feita do pincel usando o método Clone. O clone é modificado e usado para alterar o 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;
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
Observação
Independentemente do método de clone usado, as animações nunca são copiadas para o novo Freezable.
Os métodos Clone e CloneCurrentValue produzem cópias profundas do objeto congelável. Se o congelável contiver outros objetos congeláveis, eles também são clonados e tornados modificáveis. Por exemplo, se você clonar um PathGeometry congelado para torná-lo modificável, as figuras e segmentos que ele contém também serão copiados e tornados modificáveis.
Criando sua própria classe Freezable
Uma classe que deriva de Freezable ganha os seguintes recursos.
Estados especiais: um estado de leitura apenas (congelado) e um estado editável.
Segurança de threads: uma Freezable congelada pode ser compartilhada entre threads.
Notificação de alteração detalhada: Ao contrário de outros DependencyObjects, os objetos Freezable fornecem notificações de alteração quando os valores de subpropriedade são alterados.
Clonagem fácil: a classe Freezable já implementou vários métodos que produzem clones profundos.
Um Freezable é um tipo de DependencyObjecte, portanto, usa o sistema de propriedade de dependência. Suas 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 projetada com propriedades de dependência em mente. Para obter mais informações sobre o sistema de propriedades de dependência, consulte o Dependency Properties Overview.
Cada subclasse Freezable deve substituir o método CreateInstanceCore. Se sua classe usa propriedades de dependência para todos os seus dados, você está concluído.
Se sua classe contiver membros de dados de propriedade não dependentes, você também deverá substituir os seguintes métodos:
Você também deve observar as seguintes regras para aceder e gravar em membros de dados que não sejam propriedades de dependência:
No início de qualquer API que leia membros de dados de propriedade não dependentes, chame o método ReadPreamble.
No início de qualquer API que grave membros de dados de propriedade não dependentes, chame o método WritePreamble. (Depois de chamar WritePreamble em uma API, você não precisará fazer uma chamada adicional para ReadPreamble se também ler membros de dados de propriedade não dependentes.)
Chame o método WritePostscript antes de sair dos métodos que gravam em dados de propriedade que não são de dependência.
Se sua classe contiver membros de dados de propriedade de não-dependência que são objetos DependencyObject, você também deverá chamar o método OnFreezablePropertyChanged sempre que alterar um de seus valores, mesmo que esteja definindo o membro como null.
Observação
É muito importante que comeces a substituição de cada método Freezable com uma chamada para a implementação base.
Para obter um exemplo de uma classe de Freezable personalizada, consulte o Exemplo de Animação Personalizada .
Ver também
- Freezable
- Exemplo de animação personalizada
- Visão geral das propriedades de dependência
- Propriedades de Dependência Personalizadas
.NET Desktop feedback