如何在 C# WPF 中访问具有给定标记的所有 XAML 元素?

How do I access all XAML elements with a given tag in C# WPF?

在我的 XAML 中,我有以下结构中的各种错误消息:

    <Border CornerRadius="3" Background="#FFF3C7C7" Margin="6" Visibility="Collapsed" Name="quick_error" Tag="err_box">
        <TextBlock Name="err_msg" Foreground="#FFFD3434" TextWrapping="Wrap" Margin="6" ></TextBlock>
    </Border>

除名称外,块将完全相同。

我正在尝试编写代码以立即关闭所有可见错误。为此,我使用递归函数遍历我的主容器的所有子元素,然后从那里查找任何子元素,并在它们上面查找 iterate/recurse (因为错误可以在任何深度和内部父容器的任意组合)。


        private void ShowError(string errName,string errMsg)
        {
            Border errBox = (Border) mainApp.FindName(errName);
            errBox.Visibility = Visibility.Visible;
            TextBlock msg = (TextBlock) errBox.FindName("err_msg");
            msg.Text = errMsg; 
        }

        private void RecurseChildren(DependencyObject child)
        {
            if (child is Border)
            {
                Border temp = (Border)child;
            
                if (temp.Tag == "err_box")
                    ShowError("quick_error", temp.Name);
            }
            for(var i = 0; i < VisualTreeHelper.GetChildrenCount(child); i++)
            {
                RecurseChildren(VisualTreeHelper.GetChild(child, i));
            }           
        }

        private void TestRecurse()
        {
            foreach (UIElement child in mainApp.Children)
            {
                RecurseChildren(child);
            }
        }

现在,上面的代码被设计为在一个错误框(名为“quick_error”)中显示一条消息作为测试。我试图让它显示它找到的边界的名称(我知道这些名称将被找到的下一个边界覆盖,但这足以证明它正在工作所以没关系)。

但由于某种原因,没有任何显示。作为测试,我删除了 if 语句,但错误框中显示的值是“border”,这不是我 XAML 中任何边框的名称。我有两个边框值,一个名为“temp”,另一个名为“quick_error”。

我尝试只显示标记名,但如果我这样做...

ShowError("quick_error", (string)temp.Tag);

...它只是空白。为了测试,我为我的另一个边框分配了一个标签,所以它们都有一个标签,但它仍然是空白的。所以标签和名称都没有返回预期值。我做错了什么?

我找到了一个答案,该答案仅取决于属于同一类型控件的标签(在我的情况下很好,因为我使用 Border 作为错误消息):

        public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
        {
            if (depObj == null) yield return (T)Enumerable.Empty<T>();
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
            {
                DependencyObject ithChild = VisualTreeHelper.GetChild(depObj, i);
                if (ithChild == null) continue;
                if (ithChild is T t) yield return t;
                foreach (T childOfChild in FindVisualChildren<T>(ithChild)) yield return childOfChild;
            }
        }
        private void HideErrors()
        {
            foreach (Border temp in FindVisualChildren<Border>(mainApp))
            {
                if (temp.Tag != null && temp.Tag.ToString() == "err_box")
                {
                    temp.Visibility = Visibility.Collapsed;
                }
            }
        }

Findvisualchildren 是我在这个问题中找到的函数:Find all controls in WPF Window by type