No more Death March

あるSEのチラシの裏 C# WPF

WPF DependencyPropertyDescriptorのAddValueChanged

前回投稿した記事の中で触れていたDependencyPropertyDescriptorで実際にメモリリークするかどうかを試してみた。

前回の記事はこちら↓
nomoredeathmarch.hatenablog.com

画面側のコードは省くが、StackPanelとButtonを二つ配置、片方のボタンを押したらStackPanelに後述のビヘイビアを添付したTextBoxを1000個追加、もう一つのボタンを押したらStackPanelのChildrenをClearメソッドでクリアする。別途TextBlockを配置し、こちらはDespatcherTimerを使って周期的にメモリ使用量を取得して表示する。

ビヘイビアは以下の通り、TextChangedイベントを購読した場合とDependencyPropertyDescriptorのAddValueChangedメソッドを使う二通りの処理を用意しメモリの状況を確認してみた。

using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;

namespace BehaviorMemoryLeak
{
    public static class TextBoxBehavior
    {


        public static bool GetIsAttached(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsAttachedProperty);
        }

        public static void SetIsAttached(DependencyObject obj, bool value)
        {
            obj.SetValue(IsAttachedProperty, value);
        }

        public static readonly DependencyProperty IsAttachedProperty = DependencyProperty.RegisterAttached("IsAttached", typeof(bool), typeof(TextBoxBehavior), new PropertyMetadata(IsAttachedChanged));

        private static void IsAttachedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            /*
             * TextChangeを購読
            (d as TextBox).TextChanged += (sender, args) => { System.Diagnostics.Debug.WriteLine("TextChanged"); };
             */

            /* 
             * AddValueChangedでプロパティの変更を検知
            DependencyPropertyDescriptor
                .FromProperty(TextBox.TextProperty, typeof(TextBox))
                .AddValueChanged(d, (sender, args) => { System.Diagnostics.Debug.WriteLine("TextChanged"); });
             */
        }

    }
}


結果やはりDependencyPropertyDescriptorを使った方法はメモリリークしていた。WPFの基本となる依存関係プロパティの仕組み上、この辺りの制御は一通り弱参照を駆使しているのだろうなと勝手に思っていたのだがどうやら違う様子。