为什么会“this.ContentTemplate.FindName”?在其自己的模板上抛出 InvalidOperationException?
好吧...这让我难住了。我已经在我的 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 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;
}
Ok... this has me stumped. I've overridden OnContentTemplateChanged
in my UserControl
subclass. I'm checking that the value passed in for newContentTemplate
does in fact equal this.ContentTemplate
(it does) yet when I call this...
var textBox = this.ContentTemplate.FindName("EditTextBox", this);
...it throws the following exception...
"This operation is valid only on elements that have this template applied."
Per a commenter in another related question, he said you're supposed to pass in the content presenter for the control, not the control itself, so I then tried this...
var cp = FindVisualChild<ContentPresenter>(this);
var textBox = this.ContentTemplate.FindName("EditTextBox", cp);
...where FindVisualChild
is just a helper function used in MSDN's example (see below) to find the associated content presenter. While cp
is found, it too throws the same error. I'm stumped!!
Here's the helper function for reference...
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;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
在调用
FindName
方法之前显式应用模板将防止出现此错误。Explicitly applying the template before calling the
FindName
method will prevent this error.正如 John 指出的那样,OnContentTemplateChanged 在实际应用于底层 ContentPresenter 之前就被触发了。因此,您需要延迟对 FindName 的调用,直到应用它。例如:
或者,您可以将处理程序附加到 LayoutUpdated 事件,但这可能会比您想要的更频繁地触发。不过,这也可以处理隐式数据模板的情况。
像这样的东西:
As John pointed out, the OnContentTemplateChanged is being fired before it is actually applied to the underlying ContentPresenter. So you'd need to delay your call to FindName until it is applied. Something like:
Alternatively, you may be able to attach a handler to the LayoutUpdated event of the UserControl, but this may fire more often than you want. This would also handle the cases of implicit DataTemplates though.
Something like this:
直到该事件发生之后,ContentTemplate 才会应用于 ContentPresenter。虽然此时在控件上设置了 ContentTemplate 属性,但它尚未被推送到 ControlTemplate 内部的绑定,如 ContentPresenter 的 ContentTemplate。
您最终想用 ContentTemplate 做什么?可能有更好的总体方法来实现您的最终目标。
The ContentTemplate isn't applied to the ContentPresenter until after that event. While the ContentTemplate property is set on the control at that point, it hasn't been pushed down to bindings internal to the ControlTemplate, like the ContentPresenter's ContentTemplate.
What are you ultimately trying to do with the ContentTemplate? There might be a better overall approach to reach your end goal.