C# WPF - FindName 不应该返回 null
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2285491/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WPF - FindName Returns null when it should not
提问by Vaccano
FindName is broken for me :(
FindName 对我来说坏了:(
The object I am looking for is there. I have proof.
我要找的对象就在那里。我有证据。
Here is the scenario:
这是场景:
ToggleButton button = (ToggleButton)sender;
Popup popup = (Popup)button.FindName("popSelectIteration");
popup
is null but not always. Just sometimes. But even when it is set to null the child I am looking for is there.
popup
为空,但并非总是如此。有时会。但即使设置为空,我正在寻找的孩子也在那里。
I put a break point in when it was null and grabbed these two screenshots.
我在它为空时放置了一个断点并抓取了这两个屏幕截图。
The is where FindName is returning null for "popSelectIteration".
这是 FindName 为“popSelectIteration”返回 null 的地方。
But if you dig into the watch, you see that the child is there.
但是,如果您仔细观察手表,就会发现孩子就在那里。
So what am I missing? Why does FindName not find it? As you can see from the screen shot this is not a timing issue (the FindName watch is null but the direct path is fine).
那么我错过了什么?为什么 FindName 找不到它?正如您从屏幕截图中看到的,这不是时间问题(FindName 手表为空,但直接路径很好)。
Is there a better way to find a control?
有没有更好的方法来找到控件?
Side Note:If you are intersted in the XAML for the toggle button in question it can be found in this question: WPF - FrameworkElement - Enumerate all decendents?.
旁注:如果您对相关切换按钮的 XAML感兴趣,可以在以下问题中找到:WPF - FrameworkElement - Enumerate all decendents?.
Update: I did some digging to see why this fails some times and other times it works. I have an animation that calls NameScope.SetNameScope((DependencyObject)form, new NameScope());
(Full method code here). Right after that call the FindName starts to fail.
更新:我做了一些挖掘,看看为什么这有时会失败,有时会起作用。我有一个调用的动画NameScope.SetNameScope((DependencyObject)form, new NameScope());
(此处为完整方法代码)。在那次调用之后, FindName 开始失败。
I don't really understand that call. I think I copied and pasted the code. Anyway, I commented it out. But I would love know why this is failing.
我真的不明白这个电话。我想我复制并粘贴了代码。反正我是注释掉了。但我很想知道为什么这会失败。
回答by Patrick Klug
I would guess it has to do with the difference between the visual and logical tree. The control is in the logical tree but maybe the template for this control has not been applied yet and therefore FindName won't return anything useful.
我猜这与视觉树和逻辑树之间的区别有关。该控件位于逻辑树中,但可能尚未应用此控件的模板,因此 FindName 不会返回任何有用的信息。
You could try to call ApplyTemplate(); on the container first.
您可以尝试调用 ApplyTemplate(); 首先在容器上。
This would also explain why it returns something sometimes.
这也可以解释为什么它有时会返回一些东西。
回答by Tigran
I would suggest to avoid using FindName function, based on my experience, expecially problematic when you try to find something in the DataTemplate applied to some control. Instead , if it possible (based on your software architecture) declare Popup in XAML and refer to it like resource or use Binding to set some Model property to it's reference. Good luck.
根据我的经验,我建议避免使用 FindName 函数,当您尝试在应用于某些控件的 DataTemplate 中查找某些内容时,这特别有问题。相反,如果可能(基于您的软件架构)在 XAML 中声明 Popup 并像资源一样引用它,或者使用绑定将一些模型属性设置为它的引用。祝你好运。
回答by Shrike
Try
尝试
LogicalTreeHelper.FindLogicalNode(button, "popSelectIteration");
回答by Rover
Try to use button.FindResource("popSelectIteration")
尝试使用 button.FindResource("popSelectIteration")
回答by doers
I have meet the same question now, but i use the method like below:
我现在遇到了同样的问题,但我使用如下方法:
#region Override - OnApplyTemplate
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
this.PART_ListViewLeft = GetTemplateChild(cPART_ListViewLeft) as ListView;
this.PART_ListViewCenter = GetTemplateChild(cPART_ListViewCenter) as ListView;
this.PART_ListViewRight = GetTemplateChild(cPART_ListViewRight) as ListView;
this.PART_GridViewLeft = GetTemplateChild(cPART_GridViewLeft) as DsxGridView;
this.PART_GridViewCenter = GetTemplateChild(cPART_GridViewCenter) as DsxGridView;
this.PART_GridViewRight = GetTemplateChild(cPART_GridViewRight) as DsxGridView;
if(this.PART_ListViewLeft!=null)
this.PART_ListViewLeft .AlternationCount = this.AlternatingRowBrushes.Count;
if(this.PART_ListViewCenter!=null)
this.PART_ListViewCenter .AlternationCount = this.AlternatingRowBrushes.Count;
if(this.PART_ListViewRight!=null)
this.PART_ListViewRight .AlternationCount = this.AlternatingRowBrushes.Count;
// ApplyTempleted = true;
CreateColumnLayout();
}
#endregion
if the Control is dynamic create and of which or whose container the 'Visibility' is set to hide or Collapsed ,then the code "this.PART_ListViewLeft = GetTemplateChild(cPART_ListViewLeft) as ListView;" will return null always, the reason is clearly: the datatemplete has not yet been applied before OnApplyTemplate being called!!!!!!! so your question should be the same one!! good luck!
如果控件是动态创建的,并且“可见性”设置为隐藏或折叠的容器,则代码“this.PART_ListViewLeft = GetTemplateChild(cPART_ListViewLeft) as ListView;” 总是会返回 null,原因很明显:在 OnApplyTemplate 被调用之前,datatemplete 还没有被应用!!!!!!!所以你的问题应该是一样的!!祝你好运!
回答by Dilyan Rusev
In my experience, this happens when you add items via code-behind. I've found that you can fool FindName()
(or the animation framework) via name scopes. That is, when you create your control, you do
根据我的经验,当您通过代码隐藏添加项目时会发生这种情况。我发现您可以FindName()
通过名称范围来欺骗(或动画框架)。也就是说,当您创建控件时,您会
NameScope.GetNameScope(yourContainer).RegisterName("name of your control", yourControlInstance);
For this to work reliably, though, you must make sure that you unregister the name:
但是,为了使其可靠地工作,您必须确保取消注册该名称:
NameScope.GetNameScope(yourContainer).UnregisterName("name of your control");
Posting this for future reference.
发布此信息以供将来参考。
回答by Zahid Ali Mohammed
ellipseStoryboard.Children.Add(myRectAnimation); containerCanvas.Children.Add(myPath); After you add register the controls like RegisterName("TextBlock1", Var_TextBox); or RegisterName(myRectAnimation.Name,myRectAnimation); RegisterName(myPath.Name,myPath);
ellipseStoryboard.Children.Add(myRectAnimation); containerCanvas.Children.Add(myPath); 添加注册控件后,如 RegisterName("TextBlock1", Var_TextBox); 或 RegisterName(myRectAnimation.Name,myRectAnimation); 注册名(myPath.Name,myPath);
回答by Gh61
Little late to the party (and not actually answer to OP question), but
参加聚会有点晚(实际上并没有回答 OP 问题),但是
when you add elements dynamically, they are not findable by FindName
.
You need to register them by calling RegisterName
.
当您动态添加元素时,它们无法通过FindName
. 您需要通过调用注册它们RegisterName
。
Example:
例子:
Button myButton = new Button();
myButton.Content = generateNumber();
myButton.Name = "button_" + generateNumber;
RegisterName(myButton.Name, myButton);
Panel.Children.Add(myButton);
object o = Panel.FindName(myButton.Name);
Maybe someone might find this useful.
也许有人会发现这很有用。