在Silverlight中查找所有TextBox控件的通用方法

时间:2009-03-02 21:45:38

标签: silverlight

我在页面上有几个Silverlight控件,并希望查询TextBox类型的所有控件并使其正常工作。

现在我正在处理的Silverlight表单可以添加更多的TextBox控件。因此,当我测试TextBox控件是否有值时,我可以这样做:

if (this.TextBox.Control.value.Text() != String.Empty)
{
    // do whatever
}

但我宁愿灵活,我可以在任何Silverlight表单上使用它,无论我有多少TextBox控件。

关于如何做到这一点的任何想法?

5 个答案:

答案 0 :(得分:14)

我已经遇到过这个问题并在此处通知:http://megasnippets.com/en/source-codes/silverlight/Get_all_child_controls_recursively_in_Silverlight

这里有一个通用方法可以在VisualTree中以递归方式查找所有TextBox:

IEnumerable<DependencyObject> GetChildrenRecursively(DependencyObject root)
{
    List<DependencyObject> children = new List<DependencyObject>();
    children.Add(root);
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(root); i++)
        children.AddRange(GetChildrenRecursively(VisualTreeHelper.GetChild(root, i)));

    return children;
}

使用此方法查找所有TextBox:

var textBoxes = GetChildrenRecursively(LayoutRoot).OfType<TextBox>();

答案 1 :(得分:10)

听起来你需要像下面的GetTextBox这样的递归例程:

void Page_Loaded(object sender, RoutedEventArgs e)
{
    // Instantiate a list of TextBoxes
    List<TextBox> textBoxList = new List<TextBox>();

    // Call GetTextBoxes function, passing in the root element,
    // and the empty list of textboxes (LayoutRoot in this example)
    GetTextBoxes(this.LayoutRoot, textBoxList);

    // Now textBoxList contains a list of all the text boxes on your page.
    // Find all the non empty textboxes, and put them into a list.
    var nonEmptyTextBoxList = textBoxList.Where(txt => txt.Text != string.Empty).ToList();

    // Do something with each non empty textbox.
    nonEmptyTextBoxList.ForEach(txt => Debug.WriteLine(txt.Text));
}

private void GetTextBoxes(UIElement uiElement, List<TextBox> textBoxList)
{
    TextBox textBox = uiElement as TextBox;
    if (textBox != null)
    {
        // If the UIElement is a Textbox, add it to the list.
        textBoxList.Add(textBox);
    }
    else
    {
        Panel panel = uiElement as Panel;
        if (panel != null)
        {
            // If the UIElement is a panel, then loop through it's children
            foreach (UIElement child in panel.Children)
            {
                GetTextBoxes(child, textBoxList);
            }
        }
    }
}

实例化一个空文本框列表。调用GetTextBoxes,传入页面上的根控件(在我的例子中,就是this.LayoutRoot),GetTextBoxes应递归循环遍历该控件后代的每个UI元素,测试它是否是TextBox(添加它)列表)或小组,可能有它自己的后代来递归。

希望有所帮助。 :)

答案 2 :(得分:3)

从最顶层的面板中,您可以执行此操作(我的网格称为ContentGrid)

var textBoxes = this.ContentGrid.Children.OfType<TextBox>();
var nonEmptyTextboxes = textBoxes.Where(t => !String.IsNullOrEmpty(t.Text));
foreach (var textBox in nonEmptyTextboxes)
{
    //Do Something
}

但是,这只会找到直接子项的文本框。像下面这样的某种递归会有所帮助,但我认为必须有更好的方法。

private List<TextBox> SearchForTextBoxes(Panel panel)
{
    List<TextBox> list = new List<TextBox>();
    list.AddRange(panel.Children.OfType<TextBox>()
        .Where(t => !String.IsNullOrEmpty(t.Text)));

    var panels = panel.Children.OfType<Panel>();
    foreach (var childPanel in panels)
    {
        list.AddRange(SearchForTextBoxes(childPanel));
    }
    return list;
}

答案 3 :(得分:3)

取出Scott's initial idea并对其进行扩展以便

  1. 使用泛型,因此它可以轻松应对多种控件类型。
  2. 支持更多容器类型。在我的WP7中,我需要支持panaorama,滚动查看器等......这些不是Panel。所以这允许支持它们。
  3. 最大的问题是字符串比较,特别是在Panel和derrived项目上。
  4. 代码:

    private static void GetControls<T>(UIElement uiElement, List<T> controlList) where T : UIElement
    {
        var frameworkFullName = uiElement.GetType().FullName;
        if (frameworkFullName == typeof(T).FullName)
        {
            controlList.Add(uiElement as T);
            return;
        }
    
        if (frameworkFullName == typeof(Panel).FullName ||
            frameworkFullName == typeof(Grid).FullName ||
            frameworkFullName == typeof(StackPanel).FullName)
        {
            foreach (var child in (uiElement as Panel).Children)
            {
                GetControls(child, controlList);
            }
            return;
        }
    
        if (frameworkFullName == typeof(Panorama).FullName)
        {
            foreach (PanoramaItem child in (uiElement as Panorama).Items)
            {
                var contentElement = child.Content as FrameworkElement;
                if (contentElement != null)
                {
                    GetControls(contentElement, controlList);
                }
            }
            return;
        }
    
        if (frameworkFullName == typeof(ScrollViewer).FullName)
        {
            var contentElement = (uiElement as ScrollViewer).Content as FrameworkElement;
            if (contentElement != null)
            {
                GetControls(contentElement, controlList);
            }
            return;
        }
    }
    

答案 4 :(得分:1)

与上述想法类似的逻辑也可以处理具有“内容”属性的控件,如TabItems和Scrollviewers,其中子级可能嵌入在较低级别。找到所有孩子:

   IEnumerable<DependencyObject> GetControlsRecursive(DependencyObject root)
   {
       List<DependencyObject> elts = new List<DependencyObject>();
       elts.Add(root);
       string type = root.GetType().ToString().Replace("System.Windows.Controls.", "");
       switch (root.GetType().ToString().Replace("System.Windows.Controls.", ""))
       {
           case "TabItem":
               var TabItem = (TabItem)root;
               elts.AddRange(GetControlsRecursive((DependencyObject)TabItem.Content));
               break;
           case "ScrollViewer":
               var Scroll = (ScrollViewer)root;
               elts.AddRange(GetControlsRecursive((DependencyObject) Scroll.Content));
               break;
           default: //controls that have visual children go here
               for (int i = 0; i < VisualTreeHelper.GetChildrenCount(root); i++) elts.AddRange(GetControlsRecursive(VisualTreeHelper.GetChild(root, i)));
               break;
       }
       return elts;
   }