好的......这让我很难过。我在UserControl中覆盖了OnContentTemplateChanged。我正在检查传入newContentTemplate的值实际上是否等于this.ContentTemplate(它确实),但是当我调用它时...
var textBox = this.ContentTemplate.FindName("EditTextBox", this);
...它抛出以下异常......
“此操作仅对已应用此模板的元素有效。”
根据另一个相关问题的评论者,他说你应该传入内容主持人来控制,而不是控件本身,所以我试了这个......
var cp = FindVisualChild<ContentPresenter>(this);
var textBox = this.ContentTemplate.FindName("EditTextBox", cp);
其中FindVisualChild只是MSDN示例中使用的辅助函数(见下文),用于查找关联的内容演示者。找到“cp”时,它也会抛出同样的错误。我很难过!
这是辅助函数供参考......
private childItem FindVisualChild<childItem>(DependencyObject obj)
where childItem : DependencyObject
{
for(int i = 0 ; i < VisualTreeHelper.GetChildrenCount(obj) ; i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if(child != null && child is childItem)
return (childItem)child;
else
{
childItem childOfChild = FindVisualChild<childItem>(child);
if(childOfChild != null)
return childOfChild;
}
}
return null;
}
中号
答案 0 :(得分:10)
在调用FindName
方法之前显式应用模板可以防止出现此错误。
this.ApplyTemplate();
答案 1 :(得分:4)
正如John指出的那样,OnContentTemplateChanged在实际应用于底层ContentPresenter之前就被触发了。因此,在应用FindName之前,您需要延迟对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";
}
答案 2 :(得分:0)
在该事件发生之后,ContentTemplate才会应用于ContentPresenter。虽然此时在控件上设置了ContentTemplate属性,但它尚未被推送到ControlTemplate内部的绑定,如ContentPresenter的ContentTemplate。
您最终尝试使用ContentTemplate做什么?可能有更好的整体方法来实现您的最终目标。