【问题标题】:WPF - FindName Returns null when it should notWPF - FindName 不应该返回 null
【发布时间】:2011-01-18 03:13:32
【问题描述】:

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());(完整方法代码here)的动画。在那次调用之后,FindName 开始失败。

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

【问题讨论】:

    标签: c# wpf findname


    【解决方案1】:

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

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

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

    【讨论】:

    • 为我工作。 Template.FindName() 遇到了这个问题
    • 这对我有用,对于最初隐藏的控件或最初不可见的选项卡上的控件来说,这是一个问题。
    • 我遇到了带有 ComboBox 的 GetTemplateChild("PART_EditableTextBox") 问题。事先调用 ApplyTemplate() 解决了这个问题。谢谢!
    • 覆盖模板更改元数据以将绑定附加到菜单项时的类似情况。工作得很好。
    【解决方案2】:

    试试

    LogicalTreeHelper.FindLogicalNode(button, "popSelectIteration");
    

    【讨论】:

    • 这只是发生在我身上!我花了2个小时,终于,我试试你的方法,效果很好!!!
    【解决方案3】:

    晚会有点晚(实际上并没有回答 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);
    

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

    【讨论】:

    • 用最简单的词语进行伟大而可行的解释。
    【解决方案4】:

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

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

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

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

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

    【讨论】:

      【解决方案5】:

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

          #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
      

      如果Control是动态创建的,并且'Visibility'被设置为隐藏或折叠,那么代码this.PART_ListViewLeft = GetTemplateChild(cPART_ListViewLeft) as ListView;将始终返回null,原因是在@之前尚未应用数据模板987654323@ 被调用。

      【讨论】:

        【解决方案6】:

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

        【讨论】:

          【解决方案7】:

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

          【讨论】:

            【解决方案8】:

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2017-01-03
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-02-14
              相关资源
              最近更新 更多