37

FindName 对我来说坏了:(

我要找的对象就在那里。我有证据。

这是场景:

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

popup为空,但并非总是如此。只是偶尔。但即使它设置为 null 我正在寻找的孩子也在那里。

我在它为空时设置了一个断点并抓取了这两个屏幕截图。

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

但如果你深入手表,你会看到孩子在那里。

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

有没有更好的方法来找到控件?

旁注:如果您对相关切换按钮的 XAML 感兴趣,可以在以下问题中找到它:WPF - FrameworkElement - Enumerate all decendents? .


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

我真的不明白那个电话。我想我复制并粘贴了代码。不管怎样,我把它注释掉了。但我很想知道为什么这会失败。

4

8 回答 8

43

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

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

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

于 2010-02-18T06:18:27.830 回答
39

尝试

LogicalTreeHelper.FindLogicalNode(button, "popSelectIteration");
于 2010-12-02T15:30:26.457 回答
7

派对迟到了(实际上并没有回答 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);

也许有人会觉得这很有用。

于 2019-10-22T09:47:26.140 回答
6

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

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

但是,要使其可靠地工作,您必须确保取消注册名称:

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

发布此内容以供将来参考。

于 2014-04-07T16:19:15.997 回答
3

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

    #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

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

于 2013-10-25T13:32:52.850 回答
1

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

于 2010-02-18T16:10:26.500 回答
-1

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

于 2013-04-03T13:47:16.523 回答
-1

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

于 2019-09-13T15:08:37.997 回答