2012年5月22日火曜日

wpf : TemplateからNameを元にコントロールを探す

ちょっとした覚書。 TemplateからNameを元にコントロールを探すにはControlTemplate.FindNameメソッドまたはFrameworkElement.GetTemplateChildメソッドを使うようです。 FrameworkElement.FindNameメソッドはTemplateの中までは探してくれないらしい。 参考サイトはこちら。

1つのTemplateが複数のコントロールに適用された場合、同じNameのコントロールがその数だけ作成されます。 なのでNameでコントロールを探すときはVisualTreeHelperを使うのではなく、名前スコープを考慮したこれらのメソッドを使うものなんだそうです。 気付くのに遅れて無駄足を踏んでしまった...

メソッドということでxamlからは使用できません。

使用例はこんな感じ。

public class CustomControl1 : Button
{
    private Label _hoge;

    public CustomControl1()
    {
        Loaded += OnLoaded;
    }

    private void OnLoaded(object sender, RoutedEventArgs e)
    {
        Updateなんたら();
    }

    protected override void OnTemplateChanged(ControlTemplate oldTemplate, ControlTemplate newTemplate)
    {
        if (IsLoaded)
            Updateなんたら();
    }

    private void Updateなんたら()
    {
        // カスタムコントロール内で使えるprotectedメソッド
        Button foo = this.GetTemplateChild("foo") as Button;

        // カスタムコントロールではない場合はこちらを使う
        Border bar = _hoge.Template.FindName("bar", _hoge) as Border;
    }
}

インスタンス化してからしか使えないのでこうなります。 カスタムコントロールのOnTemplateChangedメソッドはLoadedイベントの前に呼ばれるため、IsLoadedでインスタンスがあるかどうかを判断します。

どうでもいいけど、名前空間と名前スコープって紛らわしいですよね? そうでもない?