Общий метод для поиска всех элементов управления TextBox в Silverlight

У меня есть несколько элементов управления Silverlight на странице и вы хотите запросить все элементы управления типа TextBox и работать с ними.

Теперь форма Silverlight, над которой я работаю, может содержать больше элементов управления TextBox. Поэтому, когда я проверяю, имеет ли элемент управления TextBox значение, я мог бы сделать:

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

но я бы предпочел, если бы был гибким, что я могу использовать его в ANY Silverlight, независимо от количества элементов управления TextBox, которые у меня есть.

Любые идеи о том, как я буду это делать?

Ответ 1

Похоже, вам нужна рекурсивная подпрограмма, например GetTextBoxes:

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 children
            foreach (UIElement child in panel.Children)
            {
                GetTextBoxes(child, textBoxList);
            }
        }
    }
}

Создайте пустой список текстовых блоков. Вызовите GetTextBoxes, передав корневой элемент управления на вашей странице (в моем случае, this.LayoutRoot) и GetTextBoxes, должны рекурсивно прокручивать каждый элемент пользовательского интерфейса, который является потомком этого элемента управления, тестируя его, будь то TextBox (добавьте его к списку), или панель, у которой могут быть потомки ее собственных, чтобы пройти через.

Надеюсь, что это поможет.:)

Ответ 2

Я уже сталкивался с этой проблемой и уведомляю ее здесь: http://megasnippets.com/en/source-codes/silverlight/Get_all_child_controls_recursively_in_Silverlight

Здесь у вас есть общий метод для поиска рекурсивно в VisualTree всех текстовых меток:

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

Используйте этот метод, чтобы найти все текстовые поля:

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

Ответ 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;
}

Ответ 4

Взяла начальную идею и расширила ее, чтобы она

  • Использует generics, поэтому он легко справляется с несколькими типами управления.
  • Поддерживает больше типов контейнеров. В моей WP7 мне нужно было поддерживать зрителей panaorama, прокрутки и т.д.... которые не являются панелями. Таким образом, это позволяет поддерживать их.
  • Самая большая проблема - это сравнение строк, особенно на панели и привращенных элементах.

Код:

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

Ответ 5

Подобная логика вышеприведенных идей также обрабатывает элементы управления с атрибутом "Content", таким как 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;
   }