Top > Programming > .NetFramework > WPF > PropertyAndDesigner
Last-modified: Mon, 04 Mar 2013 12:09:37 JST
Counter:2592 Today:1 Yesterday:0 Online:2
このエントリーをはてなブックマークに追加

プロパティとDesigner(デザイナ)へのフィードバック

デザイナ上へプロパティの値が反映されない問題

 WPFでカスタムユーザーインターフェースなどを作る場合に、外観に関わる任意のプロパティを設けることは良くあります。ところが、プロパティの値を変更したのにもかかわらずVisualStudio上のDesignerではその外観に変化が現れないことがあります。

 結論から言うと、ControlTemplateなどと結びつけるようにしてプロパティを設定することでデザイナ上でも外観のフィードバックが得られるようになりそうです(未検証)。

記事の内容に誤りないし、改善すべき内容があります。

問題の解決につながりそうな情報

プロパティの値が代入されるタイミング

 XAMLやプロパティウィンドウから設定したプロパティの値が代入されるタイミングは、Intializedが実行された後のタイミングです。試しにコンストラクタ上で値を検知して見ればわかると思いますが、プロパティの値には初期値が与えられていると思います。

 試しにプロパティ"EllipseColor"なるものを用意しました。UserControl中のEllipseのStrokeとFillを設定するためのプロパティです。次のソースコードのようにコンストラクタとOnInitializedメソッドで値を確認します。結果は両方ともnullとなります。これが依存プロパティである場合、さらに初期値が与えられている場合には、プロパティの値は設定された初期値となります(初期値がnullならnullが返りますが)。

        public Brush EllipseColor
        {
            get;
            set;
        }

        public UserControl1()
        {
            InitializeComponent();
            //呼び出し時にEllipseColorにはnullが与えられていることが分かる
            this.ellipse.Fill = this.EllipseColor;
            this.ellipse.Stroke = this.EllipseColor;
            if(this.EllipseColor == null)
                Console.WriteLine("null");
        }

        protected override void OnInitialized(EventArgs e)
        {
            base.OnInitialized(e);
            //呼び出し時にEllipseColorにはnullが与えられていることが分かる
            this.ellipse.Fill = this.EllipseColor;
            this.ellipse.Stroke = this.EllipseColor;
            if (this.EllipseColor == null)
                Console.WriteLine("null");
        }

 VisualStudio-WPFのデザイナは、Initializedまでに実行される内容について画面上に表示するようですが、OnInitialized時点ではプロパティの値が初期値であるために、プロパティを設定しても画面上に反映されない、という現象が起きるわけです。念のために書いておきますが、実行時にはきちんとプロパティの値は反映されます。

問題の解決

 先にも少し書きましたが、ControlTemplateなどと関連する依存プロパティとすれば動作すると思われます。これについては現在未検証です。試しに次のようにしてみました。この方法はとりあえず既存のUIを複数組み合わせたようなカスタムコントロールである場合には有効な手段のひとつかもしれません。

 先と同じパターンです。が、Ellipseに与えられているStrokeとFillプロパティを取得・設定するような構造にしてXAMLから値を設定したところ、デザイナ上でも適切に値の変更が反映されました。このことからTemplateの値を変更することが有効ではないか、と考えるに至ったわけです。

        //正常に動く場合(デザイナ上でも動いている)
        public Brush EllipseColor
        {
            get { return this.ellipse.Stroke; }
            set { this.ellipse.Stroke = value; }
        }