2009-06-10 55 views
185

我正在尋找一種方式,通過他們的類型,找到窗口的所有控件,查找WPF窗口的所有控件的類型

例如:找到所有TextBoxes,發現所有的控制實現特定的接口等

+0

雖然我們的話題,這也是相關的http://咕。 gl/i9RVx – 2012-08-14 14:01:22

+0

我還寫了一篇關於以下主題的博客文章:[在運行時修改ControlTemplate](http://wpfexperiments.blogspot.com/2012/08/modifying-controltemplate-in-style-at.html) – 2012-08-31 12:52:21

回答

365

這應該做的伎倆

public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject 
{ 
    if (depObj != null) 
    { 
     for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++) 
     { 
      DependencyObject child = VisualTreeHelper.GetChild(depObj, i); 
      if (child != null && child is T) 
      { 
       yield return (T)child; 
      } 

      foreach (T childOfChild in FindVisualChildren<T>(child)) 
      { 
       yield return childOfChild; 
      } 
     } 
    } 
} 

那麼你枚舉控件像這樣

foreach (TextBlock tb in FindVisualChildren<TextBlock>(window)) 
{ 
    // do something with tb here 
} 
+0

完美,謝謝 – 2009-06-10 23:15:31

+63

注意:如果你想讓這個工作,並發現你的窗口(例如)有0可視孩子,嘗試在Loaded事件處理程序中運行此方法。如果你在構造函數中運行它(甚至在InitializeComponent()之後),那麼可視化子項目不會被加載,並且它不起作用。 – 2009-08-28 15:02:52

11

使用幫助類VisualTreeHelperLogicalTreeHelper,具體取決於您感興趣的tree。它們都提供獲取元素的子元素的方法(儘管語法稍有不同)。我經常使用這些類查找特定類型的第一次出現,但你可以很容易地修改它來尋找該類型的所有對象:

public static DependencyObject FindInVisualTreeDown(DependencyObject obj, Type type) 
{ 
    if (obj != null) 
    { 
     if (obj.GetType() == type) 
     { 
      return obj; 
     } 

     for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) 
     { 
      DependencyObject childReturn = FindInVisualTreeDown(VisualTreeHelper.GetChild(obj, i), type); 
      if (childReturn != null) 
      { 
       return childReturn; 
      } 
     } 
    } 

    return null; 
} 
+0

+ 1解釋和帖子 但布賴斯卡爾發佈的功能,充分工作 謝謝 – 2009-06-10 23:18:25

+0

這不能解決問題的問題,而且泛型類型的答案也更加清晰。將它與使用VisualTreeHelper.GetChildrenCount(obj)結合使用可以解決問題。 然而,將其視爲一種選擇很有用。 – 2015-10-07 12:38:33

3

,這是它如何工作的向上

private T FindParent<T>(DependencyObject item, Type StopAt) where T : class 
    { 
     if (item is T) 
     { 
      return item as T; 
     } 
     else 
     { 
      DependencyObject _parent = VisualTreeHelper.GetParent(item); 
      if (_parent == null) 
      { 
       return default(T); 
      } 
      else 
      { 
       Type _type = _parent.GetType(); 
       if (StopAt != null) 
       { 
        if ((_type.IsSubclassOf(StopAt) == true) || (_type == StopAt)) 
        { 
         return null; 
        } 
       } 

       if ((_type.IsSubclassOf(typeof(T)) == true) || (_type == typeof(T))) 
       { 
        return _parent as T; 
       } 
       else 
       { 
        return FindParent<T>(_parent, StopAt); 
       } 
      } 
     } 
    } 
59

這是最簡單的方法:

IEnumerable<myType> collection = control.Children.OfType<myType>(); 

,其中控制是窗口的根元素。

4

獲取特定類型的所有孩子的列表,你可以使用:

private static IEnumerable<DependencyObject> FindInVisualTreeDown(DependencyObject obj, Type type) 
{ 
    if (obj != null) 
    { 
     if (obj.GetType() == type) 
     { 
      yield return obj; 
     } 

     for (var i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) 
     { 
      foreach (var child in FindInVisualTreeDown(VisualTreeHelper.GetChild(obj, i), type)) 
      { 
       if (child != null) 
       { 
        yield return child; 
       } 
      } 
     } 
    } 

    yield break; 
} 
7

我發現在上面的幾個示例中使用的行VisualTreeHelper.GetChildrenCount(depObj),不會返回GroupBoxes的非零計數,特別是在GroupBox包含Grid的情況下,並且Grid包含子元素。我相信這可能是因爲GroupBox不允許包含多個子元素,並且這個子元素存儲在它的Content屬性中。沒有GroupBox.Children類型的屬性。我相信,我不這樣做非常有效,但我修改在這條產業鏈的第一個「FindVisualChildren」舉例如下:

public IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject 
    { 
     if (depObj != null) 
     { 
      int depObjCount = VisualTreeHelper.GetChildrenCount(depObj); 
      for (int i = 0; i <depObjCount; i++) 
      { 
       DependencyObject child = VisualTreeHelper.GetChild(depObj, i); 
       if (child != null && child is T) 
       { 
        yield return (T)child; 
       } 

       if (child is GroupBox) 
       { 
        GroupBox gb = child as GroupBox; 
        Object gpchild = gb.Content; 
        if (gpchild is T) 
        { 
         yield return (T)child; 
         child = gpchild as T; 
        } 
       } 

       foreach (T childOfChild in FindVisualChildren<T>(child)) 
       { 
        yield return childOfChild; 
       } 
      } 
     } 
    } 
4

小改動,遞歸這樣你就可以例如找到的子標籤控件一個選項卡控件。

public static DependencyObject FindInVisualTreeDown(DependencyObject obj, Type type) 
    { 
     if (obj != null) 
     { 
      for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) 
      { 
       DependencyObject child = VisualTreeHelper.GetChild(obj, i); 

       if (child.GetType() == type) 
       { 
        return child; 
       } 

       DependencyObject childReturn = FindInVisualTreeDown(child, type); 
       if (childReturn != null) 
       { 
        return childReturn; 
       } 
      } 
     } 

     return null; 
    } 
16

我適應@Bryce卡勒的回答遵循@Mathias Lykkegaard洛倫岑的建議,並使用LogicalTreeHelper。

似乎工作沒關係。;!)

public static IEnumerable<T> FindLogicalChildren<T> (DependencyObject depObj) where T : DependencyObject { 
     if(depObj != null) { 
      foreach(object rawChild in LogicalTreeHelper.GetChildren(depObj)){ 
       if(rawChild is DependencyObject) { 
        DependencyObject child = (DependencyObject)rawChild; 
        if(child is T) { 
         yield return (T)child; 
        } 

        foreach(T childOfChild in FindLogicalChildren<T>(child)) { 
         yield return childOfChild; 
        } 
       } 
      } 
     } 
    } 

(它仍然不會檢查標籤控件或網格內GroupBoxes通過@Benjamin漿果& @大衛 - [R分別提及) (也跟着@ noonand的建議&被移去的冗餘子=空)

1

這裏是另一個,緊湊型,與泛型語法:

public static IEnumerable<T> FindLogicalChildren<T>(DependencyObject obj) where T : DependencyObject 
    { 
     if (obj != null) { 
      if (obj is T) 
       yield return obj as T; 

      foreach (DependencyObject child in LogicalTreeHelper.GetChildren(obj).OfType<DependencyObject>()) 
       foreach (T c in FindLogicalChildren<T>(child)) 
        yield return c; 
     } 
    } 
1

我想添加評論,但我有低於50分,所以我只能用「答案」。 請注意,如果您使用「VisualTreeHelper」方法檢索XAML「TextBlock」對象,那麼它也將抓取XAML「Button」對象。如果通過寫入Textblock.Text參數重新初始化「TextBlock」對象,則不再能夠使用Button.Content參數更改Button文本。該按鈕將永久顯示來自Textblock.Text寫入操作寫入的文字(從當它被檢索 -

foreach (TextBlock tb in FindVisualChildren<TextBlock>(window)) 
{ 
// do something with tb here 
    tb.Text = ""; //this will overwrite Button.Content and render the 
       //Button.Content{set} permanently disabled. 
} 

要解決這個問題,你可以嘗試使用XAML「文本框」,並添加方法( 。或活動),以模仿XAMAL按鈕XAML「文本框」不爲「的TextBlock」的搜索聚集

-1

我發現它更容易不可視樹助手:

foreach (UIElement element in MainWindow.Children) { 
    if (element is TextBox) { 
     if ((element as TextBox).Text != "") 
     { 
      //Do something 
     } 
    } 
}; 
2

我的版本爲C++/CLI

template < class T, class U > 
bool Isinst(U u) 
{ 
    return dynamic_cast<T>(u) != nullptr; 
} 

template <typename T> 
    T FindVisualChildByType(Windows::UI::Xaml::DependencyObject^ element, Platform::String^ name) 
    { 
     if (Isinst<T>(element) && dynamic_cast<Windows::UI::Xaml::FrameworkElement^>(element)->Name == name) 
     { 
      return dynamic_cast<T>(element); 
     } 
     int childcount = Windows::UI::Xaml::Media::VisualTreeHelper::GetChildrenCount(element); 
     for (int i = 0; i < childcount; ++i) 
     { 
      auto childElement = FindVisualChildByType<T>(Windows::UI::Xaml::Media::VisualTreeHelper::GetChild(element, i), name); 
      if (childElement != nullptr) 
      { 
       return childElement; 
      } 
     } 
     return nullptr; 
    }; 
2

由於某種原因,這裏發佈的答案都沒有幫助我獲得給定控件中包含的給定類型的所有控件在我的MainWindow中。 我需要在一個菜單中找到所有菜單項以迭代它們。他們並不都是菜單的直接後代,所以我設法只使用上面的任何代碼來收集他們的第一個lilne。 這個擴展方法是我爲這個問題的解決方案,任何人在這裏都會繼續閱讀。

public static void FindVisualChildren<T>(this ICollection<T> children, DependencyObject depObj) where T : DependencyObject 
    { 
     if (depObj != null) 
     { 
      var brethren = LogicalTreeHelper.GetChildren(depObj); 
      var brethrenOfType = LogicalTreeHelper.GetChildren(depObj).OfType<T>(); 
      foreach (var childOfType in brethrenOfType) 
      { 
       children.Add(childOfType); 
      } 

      foreach (var rawChild in brethren) 
      { 
       if (rawChild is DependencyObject) 
       { 
        var child = rawChild as DependencyObject; 
        FindVisualChildren<T>(children, child); 
       } 
      } 
     } 
    } 

希望它有幫助。

0

真的很好的答案。

VB.NET版本:

Public Shared Iterator Function FindVisualChildren(Of T As DependencyObject)(depObj As DependencyObject) As IEnumerable(Of T) 
    If depObj IsNot Nothing Then 
     For i As Integer = 0 To VisualTreeHelper.GetChildrenCount(depObj) - 1 
      Dim child As DependencyObject = VisualTreeHelper.GetChild(depObj, i) 
      If child IsNot Nothing AndAlso TypeOf child Is T Then 
       Yield DirectCast(child, T) 
      End If 
      For Each childOfChild As T In FindVisualChildren(Of T)(child) 
       Yield childOfChild 
      Next 
     Next 
    End If 
End Function 

使用(這禁用一個窗口中的所有文本框):

 For Each tb As TextBox In FindVisualChildren(Of TextBox)(Me) 
      tb.IsEnabled = False 
     Next