2009-05-17 30 views

Trả lời

7

Class để có được một danh sách tất cả các thành phần của trẻ em của một điều khiển:

class Utility 
    { 
     private static StringBuilder sbListControls; 

     public static StringBuilder GetVisualTreeInfo(Visual element) 
     { 
      if (element == null) 
      { 
       throw new ArgumentNullException(String.Format("Element {0} is null !", element.ToString())); 
      } 

      sbListControls = new StringBuilder(); 

      GetControlsList(element, 0); 

      return sbListControls; 
     } 

     private static void GetControlsList(Visual control, int level) 
     { 
      const int indent = 4; 
      int ChildNumber = VisualTreeHelper.GetChildrenCount(control); 

      for (int i = 0; i <= ChildNumber - 1; i++) 
      { 
       Visual v = (Visual)VisualTreeHelper.GetChild(control, i); 

       sbListControls.Append(new string(' ', level * indent)); 
       sbListControls.Append(v.GetType()); 
       sbListControls.Append(Environment.NewLine); 

       if (VisualTreeHelper.GetChildrenCount(v) > 0) 
       { 
        GetControlsList(v, level + 1); 
       } 
      } 
     } 
    } 
+2

Không looping thông qua cây hợp lý là tốt hơn và hiệu quả hơn looping thông qua cây thị giác. – MegaMind

+0

'sbListControls' phải là một biến cục bộ, chỉ trong trường hợp các phương thức này được gọi cùng một lúc bởi nhiều luồng. –

14

Tôi thấy điều này trong MSDN documenation nên nó giúp.

// Enumerate all the descendants of the visual object. 
static public void EnumVisual(Visual myVisual) 
{ 
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(myVisual); i++) 
    { 
     // Retrieve child visual at specified index value. 
     Visual childVisual = (Visual)VisualTreeHelper.GetChild(myVisual, i); 

     // Do processing of the child visual object. 

     // Enumerate children of the child visual object. 
     EnumVisual(childVisual); 
    } 
} 

Có vẻ đơn giản hơn với tôi. Tôi đã sử dụng nó để tìm các hộp văn bản trong một biểu mẫu và xóa dữ liệu của chúng.

+0

Tôi đăng một câu trả lời khác dựa trên điều này thực sự trả về một 'IEnumerable ' để người dùng cuối chỉ có thể sử dụng vòng lặp thông thường, v.v. Điều này giúp liệt kê bộ sưu tập của trẻ rất đơn giản và cho phép phá thai sớm thông qua 'ngắt; 'vv Hãy xem. – BrainSlugs83

+0

Khi tôi cố gắng để tái sản xuất này tôi nhận được một lỗi trên myVisual (tức là .GetChildrenCount (** myVisual **) & .GetChild (** myVisual **, i)) nói "không thể chuyển đổi từ 'Windows.UI.Composition.Visual 'to' Windows.UI.Xaml.DependencyObject '"? Các giải pháp WPF có hoạt động trong môi trường UWP không? Tôi có sử dụng sai chỉ thị bằng cách sử dụng (Windows.UI.Composition)? – gaw

0

Một biến thể nhẹ vào câu trả lời MSDN ... chỉ cần vượt qua trong một danh sách rỗng của các đối tượng trực quan vào nó và bộ sưu tập của bạn sẽ được áp dụng với tất cả các hình ảnh con:

/// <summary> 
/// Enumerate all the descendants (children) of a visual object. 
/// </summary> 
/// <param name="parent">Starting visual (parent).</param> 
/// <param name="collection">Collection, into which is placed all of the descendant visuals.</param> 
public static void EnumVisual(Visual parent, List<Visual> collection) 
{ 
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++) 
    { 
     // Get the child visual at specified index value. 
     Visual childVisual = (Visual)VisualTreeHelper.GetChild(parent, i); 

     // Add the child visual object to the collection. 
     collection.Add(childVisual); 

     // Recursively enumerate children of the child visual object. 
     EnumVisual(childVisual, collection); 
    } 
} 
+0

Tôi đăng một câu trả lời khác dựa trên thực tế bạn trả về một 'IEnumerable ' để người dùng cuối chỉ có thể sử dụng vòng lặp thông thường, v.v. Điều này giúp tiết kiệm chi phí cho việc tạo danh sách và cho phép phá thai sớm thông qua 'ngắt; 'vv Hãy xem. – BrainSlugs83

8

Bằng cách này là vượt trội so với các Phương thức MSDN, trong đó nó có thể tái sử dụng, và nó cho phép hủy bỏ vòng lặp sớm (tức là thông qua, break;, v.v.) - nó tối ưu hóa vòng lặp for ở chỗ nó lưu một lời gọi phương thức cho mỗi lần lặp - và nó cũng cho phép bạn sử dụng thường xuyên cho các vòng lặp thông qua một đứa trẻ của Visual, hoặc thậm chí recurse nó là trẻ em và đó là trẻ em lớn - vì vậy nó đơn giản hơn nhiều để tiêu thụ.

Để tiêu thụ nó, bạn chỉ có thể viết một vòng lặp foreach thường xuyên (hoặc thậm chí sử dụng LINQ):

foreach (var ctrl in myWindow.GetChildren()) 
{ 
    // Process children here! 
} 

Hoặc nếu bạn không muốn để recurse:

foreach (var ctrl in myWindow.GetChildren(false)) 
{ 
    // Process children here! 
} 

Để làm cho nó công việc, bạn chỉ cần đặt phương thức mở rộng này vào bất kỳ lớp tĩnh nào và sau đó bạn sẽ có thể viết mã như trên bất cứ lúc nào bạn muốn:

public static IEnumerable<Visual> GetChildren(this Visual parent, bool recurse = true) 
{ 
    if (parent != null) 
    { 
     int count = VisualTreeHelper.GetChildrenCount(parent); 
     for (int i = 0; i < count; i++) 
     { 
      // Retrieve child visual at specified index value. 
      var child = VisualTreeHelper.GetChild(parent, i) as Visual; 

      if (child != null) 
      { 
       yield return child; 

       if (recurse) 
       { 
        foreach (var grandChild in child.GetChildren(true)) 
        { 
         yield return grandChild; 
        } 
       } 
      } 
     } 
    } 
} 

Ngoài ra, nếu bạn không thích đệ quy được bật theo mặc định, bạn có thể thay đổi tuyên bố của phương thức tiện ích mở rộng để có recurse = false là hành vi mặc định.

1

Tôi đã sử dụng các mục sau để có tất cả các điều khiển.

public static IList<Control> GetControls(this DependencyObject parent) 
    {    
     var result = new List<Control>(); 
     for (int x = 0; x < VisualTreeHelper.GetChildrenCount(parent); x++) 
     { 
      DependencyObject child = VisualTreeHelper.GetChild(parent, x); 
      var instance = child as Control; 

      if (null != instance) 
       result.Add(instance); 

      result.AddRange(child.GetControls()); 
     } 
     return result; 
    } 
Các vấn đề liên quan