はじめに
WPFは遅いです。それはとてもとても。
ちょっとしたサンプルレベルで動作させてるうちは問題なくても、データ量が増えた場合等は、かなりパフォーマンスを意識した作りをしないとアプリケーションとして破綻してしまうことがあります。
というわけで、WPFのパフォーマンスで気を付けた方が良い点とかを気づいたレベルで、覚書しておきます。
DependencyPropertyへのアクセス
通常DependencyPropertyは、下記のように定義されます。(VisualStudio上でpropdpとタイプしてTab2回で展開されたものです。Resharperを利用されている方はdependencypropertyのキーワードでほぼ同じsnippetが用意されています。)
public int MyProperty
{
get { return (int)GetValue(MyPropertyProperty); }
set { SetValue(MyPropertyProperty, value); }
}
// Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.Register("MyProperty", typeof(int), typeof(ownerclass), new PropertyMetadata(0));
で、コードからはCLR PropertyとしてラップされたDependency Propertyにアクセスするのですが、これが通常のCLR Propertyと比べると格段にアクセスが遅いです。興味のある方は、ReferenceSourceでGetValueの内部を見てもらうとして、Snippetとして見えてる範囲でもアクセスのたびにUnboxingが発生して、嫌な感じですよね。
CompositeTarget.RenderingイベントやControl.MouseMoveイベント内など、頻繁に呼び出される箇所で複数のDependencyPropertyを参照しているのであれば、一度フィールドにキャッシュしたうえでアクセスを検討することをお勧めします。
対策
というわけ、Snippetを以下のように変更してみました。
private int _myProperty;
public int MyProperty
{
get { return _myProperty; }
set { SetValue(MyPropertyProperty, value); }
}
// Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.Register("MyProperty", typeof(int), typeof(ownerclass),
new PropertyMetadata(0, (s, e) => ((ownerclass)s)._myProperty = (int)e.NewValue));
対応はgetterのみです。秒間何回もSetterが呼び出されることはほぼないと思われるので、これで十分でしょう。
もちろん、DependencyPropertyとして値を保持しているのと、ローカルフィールドとして保持するのの2重管理になるので、メモリ使用量が増えるとかはありますが、影響は限定的だと思います。
おわりに
ところで②はあるのか?