20

わかりました...これは私を困惑させました。サブクラスでオーバーライドOnContentTemplateChangedしました。UserControlこれを呼び出すと、 for に渡された値がnewContentTemplate実際に等しいthis.ContentTemplate(等しい) ことを確認しています...

var textBox = this.ContentTemplate.FindName("EditTextBox", this);

...次の例外がスローされます...

「この操作は、このテンプレートが適用されている要素に対してのみ有効です。」

別の関連する質問のコメント者によると、彼は、コントロール自体ではなく、コントロールのコンテンツ プレゼンターを渡すことになっていると述べたので、これを試しました...

var cp = FindVisualChild<ContentPresenter>(this);

var textBox = this.ContentTemplate.FindName("EditTextBox", cp);

...whereFindVisualChildは、関連するコンテンツ プレゼンターを見つけるために MSDN の例 (以下を参照) で使用される単なるヘルパー関数です。が見つかってcpも、同じエラーがスローされます。私は困惑しています!

参照用のヘルパー関数は次のとおりです...

private TChildItem FindVisualChild<TChildItem>(DependencyObject obj)
where TChildItem : DependencyObject {

    for(int i = 0 ; i < VisualTreeHelper.GetChildrenCount(obj) ; i++) {

        var child = VisualTreeHelper.GetChild(obj, i);

        if(child is TChildItem typedChild) {
            return typedChild;
        }
        else {
            var childOfChild = FindVisualChild<TChildItem>(child);
            if(childOfChild != null)
                return childOfChild;
        }
    }

    return null;
}
4

3 に答える 3

18

メソッドを呼び出す前にテンプレートを明示的に適用するFindNameと、このエラーを防ぐことができます。

this.ApplyTemplate(); 
于 2013-03-17T23:46:07.683 に答える
4

John が指摘したように、OnContentTemplateChanged は、基になる ContentPresenter に実際に適用される前に起動されています。そのため、FindName が適用されるまで呼び出しを遅らせる必要があります。何かのようなもの:

protected override void OnContentTemplateChanged(DataTemplate oldContentTemplate, DataTemplate newContentTemplate) {
    base.OnContentTemplateChanged(oldContentTemplate, newContentTemplate);

    this.Dispatcher.BeginInvoke((Action)(() => {
        var cp = FindVisualChild<ContentPresenter>(this);
        var textBox = this.ContentTemplate.FindName("EditTextBox", cp) as TextBox;
        textBox.Text = "Found in OnContentTemplateChanged";
    }), DispatcherPriority.DataBind);
}

別の方法として、ハンドラーを UserControl のLayoutUpdatedイベントにアタッチすることもできますが、これは必要以上に頻繁に発生する可能性があります。ただし、これは暗黙的な DataTemplates のケースも処理します。

このようなもの:

public UserControl1() {
    InitializeComponent();
    this.LayoutUpdated += new EventHandler(UserControl1_LayoutUpdated);
}

void UserControl1_LayoutUpdated(object sender, EventArgs e) {
    var cp = FindVisualChild<ContentPresenter>(this);
    var textBox = this.ContentTemplate.FindName("EditTextBox", cp) as TextBox;
    textBox.Text = "Found in UserControl1_LayoutUpdated";
}
于 2011-04-19T17:24:32.950 に答える
0

ContentTemplate は、そのイベントの後まで ContentPresenter に適用されません。その時点で ContentTemplate プロパティがコントロールに設定されていますが、ContentPresenter の ContentTemplate のように、ControlTemplate 内部のバインディングにはプッシュされていません。

ContentTemplate で最終的に何をしようとしていますか? 最終目標を達成するためのより良い全体的なアプローチがあるかもしれません。

于 2011-04-15T19:12:32.577 に答える