WPF - FindName 在不应返回 null 时返回 null

发布于 2024-08-21 18:50:43 字数 965 浏览 5 评论 0原文

FindName 对我来说已经损坏了:(

我正在寻找的对象在那里。我有证据。

情况如下:

ToggleButton button = (ToggleButton)sender;
Popup popup = (Popup)button.FindName("popSelectIteration");

popup 为 null 但并不总是。只是有时。但即使它设置为 null我正在寻找的孩子就在那里。

它为空时,我在其中放置了一个断点,并抓取了这两个屏幕截图,

这就是 FindName 为“popSelectIteration”返回空的地方。

当 那么我错过了

什么?为什么 FindName 找不到它?正如您从屏幕截图中看到的那样,这不是时间问题(FindName 手表为空,但直接路径没问题)

。找到一个控件?

旁注:如果您对相关切换按钮的 XAML 感兴趣,可以在以下问题中找到它:WPF - FrameworkElement - 枚举所有后代?


更新:我做了一些挖掘,看看为什么有时会失败,有时会失败作品。我有一个调用 NameScope.SetNameScope((DependencyObject)form, new NameScope()); 的动画(完整方法代码 此处)。在该调用之后,FindName 开始失败。

我真的不太明白这个电话。我想我复制并粘贴了代码。无论如何,我已经注释掉了。但我很想知道为什么会失败。

FindName is broken for me :(

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.

I put a break point in when it was null and grabbed these two screenshots.

The is where FindName is returning null for "popSelectIteration".

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).

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?.


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.

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

小巷里的女流氓 2024-08-28 18:50:43

我猜这与视觉树和逻辑树之间的差异有关。该控件位于逻辑树中,但可能尚未应用该控件的模板,因此 FindName 将不会返回任何有用的内容。

您可以尝试调用ApplyTemplate();首先在容器上。

这也可以解释为什么它有时会返回一些东西。

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.

You could try to call ApplyTemplate(); on the container first.

This would also explain why it returns something sometimes.

画尸师 2024-08-28 18:50:43

尝试

LogicalTreeHelper.FindLogicalNode(button, "popSelectIteration");

Try

LogicalTreeHelper.FindLogicalNode(button, "popSelectIteration");
摘星┃星的人 2024-08-28 18:50:43

参加聚会有点晚了(实际上并没有回答OP问题),但是

当您动态添加元素时,FindName无法找到它们。
您需要通过调用RegisterName来注册它们。

示例:

string number = GenerateNumber();

Button myButton = new Button();
myButton.Content = number;
myButton.Name = "button_" + number;

RegisterName(myButton.Name, myButton);

Panel.Children.Add(myButton);
object o = Panel.FindName(myButton.Name);

也许有人会发现这很有用。

Little late to the party (and not actually answer to OP question), but

when you add elements dynamically, they are not findable by FindName.
You need to register them by calling RegisterName.

Example:

string number = GenerateNumber();

Button myButton = new Button();
myButton.Content = number;
myButton.Name = "button_" + number;

RegisterName(myButton.Name, myButton);

Panel.Children.Add(myButton);
object o = Panel.FindName(myButton.Name);

Maybe someone might find this useful.

原来是傀儡 2024-08-28 18:50:43

根据我的经验,当您通过代码隐藏添加项目时会发生这种情况。我发现您可以通过名称范围来欺骗 FindName()(或动画框架)。也就是说,当您创建控件时,您必须执行

    NameScope.GetNameScope(yourContainer).RegisterName("name of your control", yourControlInstance);

此操作才能可靠地工作,但是,您必须确保取消注册该名称:

    NameScope.GetNameScope(yourContainer).UnregisterName("name of your control");

发布此名称以供将来参考。

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

    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.

写给空气的情书 2024-08-28 18:50:43

我现在遇到了同样的问题,但我使用这样的方法:

    #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

如果控件是动态创建的,并且其“可见性”设置为隐藏或折叠,则代码 this.PART_ListViewLeft = GetTemplateChild (cPART_ListViewLeft) as ListView; 将始终返回 null,原因是在调用 OnApplyTemplate 之前尚未应用数据模板。

I have meet the same question now, but I use the method like so:

    #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 always return null, the reason is that the datatemplete has not yet been applied before OnApplyTemplate being called.

烙印 2024-08-28 18:50:43

根据我的经验,我建议避免使用 FindName 函数,当您尝试在应用于某些控件的 DataTemplate 中查找某些内容时,尤其会出现问题。
相反,如果可能的话(基于您的软件架构)在 XAML 中声明 Popup 并
像资源一样引用它或使用 Binding 将某些模型属性设置为其引用。
祝你好运。

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.

智商已欠费 2024-08-28 18:50:43

尝试使用 button.FindResource("popSelectIteration")

Try to use button.FindResource("popSelectIteration")

触ぅ动初心 2024-08-28 18:50:43

ellipseStoryboard.Children.Add(myRectAnimation);
containerCanvas.Children.Add(myPath);
添加注册控件后,例如
RegisterName("TextBlock1", Var_TextBox);
或者
RegisterName(myRectAnimation.Name,myRectAnimation);
注册名称(myPath.Name,myPath);

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);

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文