Freezable オブジェクトの概要Freezable Objects Overview

このトピックでは、アプリケーションのパフォーマンス向上に役立つ特殊な機能を提供する Freezable オブジェクトを効果的に使用し、作成する方法について説明します。This topic describes how to effectively use and create Freezable objects, which provide special features that can help improve application performance. freezable オブジェクトの例として、ブラシ、ペン、変換、ジオメトリ、アニメーションなどがあります。Examples of freezable objects include brushes, pens, transformations, geometries, and animations.

Freezable とはWhat Is a Freezable?

Freezable は、非固定と固定という 2 つの状態を持つ特殊な型のオブジェクトです。A Freezable is a special type of object that has two states: unfrozen and frozen. 非固定の場合、Freezable は他のオブジェクトと同じように動作します。When unfrozen, a Freezable appears to behave like any other object. 固定されると、Freezable を変更できなくなります。When frozen, a Freezable can no longer be modified.

Freezable には、オブジェクトに対する変更をオブザーバーに通知する Changed イベントが用意されています。A Freezable provides a Changed event to notify observers of any modifications to the object. Freezable を固定すると、変更通知にリソースを費やす必要がなくなるため、パフォーマンスが向上します。Freezing a Freezable can improve its performance, because it no longer needs to spend resources on change notifications. 固定された Freezable は複数のスレッドで共有できますが、非固定の Freezable はできません。A frozen Freezable can also be shared across threads, while an unfrozen Freezable cannot.

Freezable クラスには多くのアプリケーションがありますが、Windows Presentation Foundation (WPF)Windows Presentation Foundation (WPF) のほとんどの Freezable オブジェクトはグラフィックス サブシステムに関連しています。Although the Freezable class has many applications, most Freezable objects in Windows Presentation Foundation (WPF)Windows Presentation Foundation (WPF) are related to the graphics sub-system.

Freezable クラスによって、特定のグラフィックス システム オブジェクトを簡単に使用できるようになり、アプリケーションのパフォーマンス向上に役立ちます。The Freezable class makes it easier to use certain graphics system objects and can help improve application performance. Freezable から継承される型の例として、BrushTransformGeometry クラスなどがあります。Examples of types that inherit from Freezable include the Brush, Transform, and Geometry classes. アンマネージ リソースが含まれているため、システムでこれらのオブジェクトの変更を監視し、元のオブジェクトに変更があった場合は対応するアンマネージ リソースを更新する必要があります。Because they contain unmanaged resources, the system must monitor these objects for modifications, and then update their corresponding unmanaged resources when there is a change to the original object. グラフィックス システム オブジェクトを実際に変更していなくても、変更を実行する場合に備えて、システムではオブジェクトの監視にリソースの一部を費やす必要があります。Even if you don't actually modify a graphics system object, the system must still spend some of its resources monitoring the object, in case you do change it.

たとえば、SolidColorBrush ブラシを作成し、それを使用してボタンの背景を描画するとします。For example, suppose you create a SolidColorBrush brush and use it to paint the background of a button.

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

ボタンがレンダリングされると、WPFWPF グラフィックス サブシステムでは、提供された情報を使用してピクセルのグループが描画され、ボタンの外観が作成されます。When the button is rendered, the WPFWPF graphics sub-system uses the information you provided to paint a group of pixels to create the appearance of a button. ボタンの描画方法を説明するために単色ブラシを使用しましたが、この単色ブラシでは実際には描画を行いません。Although you used a solid color brush to describe how the button should be painted, your solid color brush doesn't actually do the painting. グラフィックス システムによって、ボタンとブラシ用の高速で低レベルのオブジェクトが生成されます。実際に画面に表示されるのはこれらのオブジェクトです。The graphics system generates fast, low-level objects for the button and the brush, and it is those objects that actually appear on the screen.

ブラシを変更する場合、それらの低レベル オブジェクトを再生成する必要があります。If you were to modify the brush, those low-level objects would have to be regenerated. freezable クラスは、生成された低レベルの対応するオブジェクトを見つけて、変更時にそれらを更新する機能をブラシに付与するものです。The freezable class is what gives a brush the ability to find its corresponding generated, low-level objects and to update them when it changes. この機能が有効な場合、ブラシは "非固定" と呼ばれます。When this ability is enabled, the brush is said to be "unfrozen."

freezable の Freeze メソッドを使用すると、この自己更新機能を無効にすることができます。A freezable's Freeze method enables you to disable this self-updating ability. この方法を使用して、ブラシを "固定"、つまり変更不可にすることができます。You can use this method to make the brush become "frozen," or unmodifiable.

注意

すべての Freezable オブジェクトを固定できるわけではありません。Not every Freezable object can be frozen. InvalidOperationException がスローされないようにするには、固定する前に、Freezable オブジェクトの CanFreeze プロパティの値を確認して固定できるかどうかを判断します。To avoid throwing an InvalidOperationException, check the value of the Freezable object's CanFreeze property to determine whether it can be frozen before attempting to freeze it.

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

freezable を変更する必要がなくなった場合は、固定するとパフォーマンスが向上します。When you no longer need to modify a freezable, freezing it provides performance benefits. この例のブラシを固定した場合、グラフィックス システムでブラシの変更を監視する必要がなくなります。If you were to freeze the brush in this example, the graphics system would no longer need to monitor it for changes. また、ブラシが変更されないことがわかっているため、グラフィックス システムで他の最適化を行うこともできます。The graphics system can also make other optimizations, because it knows the brush won't change.

注意

便宜上、明示的に固定しない限り、freezable オブジェクトは固定されないままです。For convenience, freezable objects remain unfrozen unless you explicitly freeze them.

Freezable の使用Using Freezables

固定されていない freezable の使用は、他の種類のオブジェクトの使用と同様です。Using an unfrozen freezable is like using any other type of object. 次の例では、SolidColorBrush の色は、ボタンの背景の描画に使用された後、黄色から赤に変更されます。In the following example, the color of a SolidColorBrush is changed from yellow to red after it's used to paint the background of a button. グラフィックス システムはバックグラウンドで動作しており、次に画面が更新されたときにボタンは自動的に黄色から赤に変更されます。The graphics system works behind the scenes to automatically change the button from yellow to red the next time the screen is refreshed.

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

Freezable の固定Freezing a Freezable

Freezable を変更不可にするには、その Freeze メソッドを呼び出します。To make a Freezable unmodifiable, you call its Freeze method. freezable オブジェクトを含むオブジェクトを固定すると、それらのオブジェクトも固定されます。When you freeze an object that contains freezable objects, those objects are frozen as well. たとえば、PathGeometry を固定すると、それに含まれる図とセグメントも固定されます。For example, if you freeze a PathGeometry, the figures and segments it contains would be frozen too.

次のいずれかに該当する場合、Freezable を固定できませんA Freezable can't be frozen if any of the following are true:

  • アニメーション化された、またはデータ バインドされたプロパティがあります。It has animated or data bound properties.

  • 動的リソースによって設定されるプロパティがありますIt has properties set by a dynamic resource. (動的リソースの詳細については、XAML リソースに関する記事を参照してください)。(See the XAML Resources for more information about dynamic resources.)

  • 凍結できない Freezable サブオブジェクトが含まれています。It contains Freezable sub-objects that can't be frozen.

これらの条件が false であり、Freezable を変更する予定がない場合は、前述したように、固定してパフォーマンスを向上させることをお勧めします。If these conditions are false, and you don't intend to modify the Freezable, then you should freeze it to gain the performance benefits described earlier.

freezable の Freeze メソッドを呼び出すと、変更できなくなります。Once you call a freezable's Freeze method, it can no longer be modified. 固定されたオブジェクトを変更しようとすると、InvalidOperationException がスローされます。Attempting to modify a frozen object causes an InvalidOperationException to be thrown. 次のコードでは、固定後にブラシを変更しようとしているため、例外がスローされます。The following code throws an exception, because we attempt to modify the brush after it's been frozen.


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

この例外がスローされないようにするには、IsFrozen メソッドを使用して、Freezable が固定されているかどうかを確認します。To avoid throwing this exception, you can use the IsFrozen method to determine whether a Freezable is frozen.


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


前のコード例では、Clone メソッドを使用して、固定されたオブジェクトから変更可能なコピーが作成されました。In the preceding code example, a modifiable copy was made of a frozen object using the Clone method. 次のセクションでは、複製について詳しく説明します。The next section discusses cloning in more detail.

注意

固定された freezable オブジェクトはアニメーション化できないため、Storyboard でアニメーション化しようとすると、アニメーション システムによって、固定された Freezable オブジェクトの変更可能なクローンが自動的に作成されます。Because a frozen freezable cannot be animated, the animation system will automatically create modifiable clones of frozen Freezable objects when you try to animate them with a Storyboard. 複製によるパフォーマンスのオーバーヘッドをなくすには、アニメーション化する場合にオブジェクトを固定しないでください。To eliminate the performance overhead caused by cloning, leave an object unfrozen if you intend to animate it. アニメーション化とストーリーボードの詳細については、「ストーリーボードの概要」を参照してください。For more information about animating with storyboards, see the Storyboards Overview.

マークアップからの固定Freezing from Markup

マークアップで宣言された Freezable オブジェクトを固定するには、PresentationOptions:Freeze 属性を使用します。To freeze a Freezable object declared in markup, you use the PresentationOptions:Freeze attribute. 次の例では、SolidColorBrush がページ リソースとして宣言され、固定されています。In the following example, a SolidColorBrush is declared as a page resource and frozen. これは、ボタンの背景を設定するために使用されます。It is then used to set the background of a button.

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

Freeze 属性を使用するには、プレゼンテーション オプション名前空間 http://schemas.microsoft.com/winfx/2006/xaml/presentation/options にマップする必要があります。To use the Freeze attribute, you must map to the presentation options namespace: http://schemas.microsoft.com/winfx/2006/xaml/presentation/options. PresentationOptions は、この名前空間のマッピングに推奨されるプレフィックスです。PresentationOptions is the recommended prefix for mapping this namespace:

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

すべての XAML リーダーでこの属性が認識されるわけではないため、mc:Ignorable 属性を使用して、Presentation:Freeze 属性を無視できるものとしてマークすることをお勧めします。Because not all XAML readers recognize this attribute, it's recommended that you use the mc:Ignorable Attribute to mark the Presentation:Freeze attribute as ignorable:

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

詳細については、「mc:Ignorable 属性」ページを参照してください。For more information, see the mc:Ignorable Attribute page.

Freezable の "固定解除""Unfreezing" a Freezable

固定された後に、Freezable を変更または固定解除することはできなくなります。ただし、Clone または CloneCurrentValue メソッドを使用して、固定されていない複製を作成できます。Once frozen, a Freezable can never be modified or unfrozen; however, you can create an unfrozen clone using the Clone or CloneCurrentValue method.

次の例では、ボタンの背景にブラシを設定し、そのブラシを固定しています。In the following example, the button's background is set with a brush and that brush is then frozen. 固定されていないコピーは、Clone メソッドを使用してブラシから作成されます。An unfrozen copy is made of the brush using the Clone method. ボタンの背景を黄色から赤色に変更するために、複製が変更され、使用されます。The clone is modified and used to change the button's background from yellow to red.

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

注意

使用する複製方法に関係なく、アニメーションが新しい Freezable にコピーされることはありません。Regardless of which clone method you use, animations are never copied to the new Freezable.

Clone および CloneCurrentValue メソッドを使用すると、freezable のディープ コピーが生成されます。The Clone and CloneCurrentValue methods produce deep copies of the freezable. freezable に他の固定された freezable オブジェクトが含まれている場合は、それらも複製され、変更可能になります。If the freezable contains other frozen freezable objects, they are also cloned and made modifiable. たとえば、固定された PathGeometry を複製して変更可能にすると、そこに含まれる図形とセグメントもコピーされ、変更可能になります。For example, if you clone a frozen PathGeometry to make it modifiable, the figures and segments it contains are also copied and made modifiable.

独自の Freezable クラスの作成Creating Your Own Freezable Class

Freezable から派生するクラスには、次の機能があります。A class that derives from Freezable gains the following features.

  • 特別な状態: 読み取り専用 (固定) および書き込み可能な状態。Special states: a read-only (frozen) and a writable state.

  • スレッド セーフ: 固定された Freezable はスレッド間で共有できます。Thread safety: a frozen Freezable can be shared across threads.

  • 詳細な変更通知:他の DependencyObject とは異なり、Freezable オブジェクトからは、サブプロパティ値が変更されたときに変更通知が提供されます。Detailed change notification: Unlike other DependencyObjects, Freezable objects provide change notifications when sub-property values change.

  • 簡単な複製: Freezable クラスには、ディープ クローンを生成するいくつかのメソッドが既に実装されています。Easy cloning: the Freezable class has already implemented several methods that produce deep clones.

FreezableDependencyObject の一種であるため、依存関係プロパティ システムが使用されます。A Freezable is a type of DependencyObject, and therefore uses the dependency property system. クラスのプロパティは必ずしも依存関係プロパティではありません。ただし、依存関係プロパティを使用する場合、Freezable クラスは依存関係プロパティを考慮して設計されているため、記述しなければならないコードの量が減ります。Your class properties don't have to be dependency properties, but using dependency properties will reduce the amount of code you have to write, because the Freezable class was designed with dependency properties in mind. 依存関係プロパティ システムの詳細については、「依存関係プロパティの概要」を参照してください。For more information about the dependency property system, see the Dependency Properties Overview.

すべての Freezable サブクラスで CreateInstanceCore メソッドをオーバーライドする必要があります。Every Freezable subclass must override the CreateInstanceCore method. クラスで、すべてのデータに依存関係プロパティが使用されている場合は、これで完了です。If your class uses dependency properties for all its data, you're finished.

クラスに非依存関係プロパティ データ メンバーが含まれている場合は、次のメソッドもオーバーライドする必要があります。If your class contains non-dependency property data members, you must also override the following methods:

また、依存関係プロパティではないデータ メンバーへのアクセスと書き込みについては、次の規則に従う必要があります。You must also observe the following rules for accessing and writing to data members that are not dependency properties:

  • 非依存関係プロパティ データ メンバーを読み取る API の先頭で、ReadPreamble メソッドを呼び出します。At the beginning of any API that reads non-dependency property data members, call the ReadPreamble method.

  • 非依存関係プロパティ データ メンバーを書き込む API の先頭で、WritePreamble メソッドを呼び出しますAt the beginning of any API that writes non-dependency property data members, call the WritePreamble method. (API で WritePreamble を呼び出した後に、非依存関係プロパティ データ メンバーも読み取る場合、ReadPreamble をさらに呼び出す必要はありません)。(Once you've called WritePreamble in an API, you don't need to make an additional call to ReadPreamble if you also read non-dependency property data members.)

  • 非依存関係プロパティ データ メンバーに書き込むメソッドを終了する前に、WritePostscript メソッドを呼び出します。Call the WritePostscript method before exiting methods that write to non-dependency property data members.

クラスに DependencyObject オブジェクトである非依存関係プロパティ データ メンバーが含まれている場合、メンバーを null に設定している場合でも、いずれかの値を変更するたびに OnFreezablePropertyChanged メソッドも呼び出す必要があります。If your class contains non-dependency-property data members that are DependencyObject objects, you must also call the OnFreezablePropertyChanged method each time you change one of their values, even if you're setting the member to null.

注意

基本実装を呼び出すことで、オーバーライドする各 Freezable メソッドを開始することが非常に重要です。It's very important that you begin each Freezable method you override with a call to the base implementation.

カスタムの Freezable クラスの例については、カスタム アニメーションのサンプルを参照してください。For an example of a custom Freezable class, see the Custom Animation Sample.

関連項目See also