Window에서 모든 컨트롤을 유형별로 찾는 방법을 찾고 있습니다.
예를 들어 : 모두 찾기 TextBoxes
, 특정 인터페이스를 구현하는 모든 컨트롤 찾기 등
Window에서 모든 컨트롤을 유형별로 찾는 방법을 찾고 있습니다.
예를 들어 : 모두 찾기 TextBoxes
, 특정 인터페이스를 구현하는 모든 컨트롤 찾기 등
답변:
이 트릭을해야합니다
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
}
this
전에 DependencyObject
=>this DependencyObject depObj
가장 쉬운 방법입니다.
IEnumerable<myType> collection = control.Children.OfType<myType>();
여기서 control은 창의 루트 요소입니다.
<Grid Name="Anata_wa_yoru_o_shihai_suru_ai">here buttons</Grid>
사용할 수 있습니다.Anata_wa_yoru_o_shihai_suru_ai.Children.OfType<myType>();
@Bryce Kahle의 답변을 @Mathias Lykkegaard Lorenzen의 제안과 사용에 따라 조정했습니다 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;
}
}
}
}
}
(여전히 @Benjamin Berry & @David R에서 언급 한대로 GroupBox 내부의 탭 컨트롤 또는 그리드를 확인하지 않습니다.) (또한 @noonand의 제안을 따르고 중복 자식을 제거했습니다! = null)
헬퍼 클래스를 사용 VisualTreeHelper
하거나 관심 LogicalTreeHelper
있는 트리 에 따라 다를 수 있습니다. 둘 다 요소의 하위를 가져 오는 메소드를 제공합니다 (구문이 약간 다르지만). 필자는 종종 이러한 클래스를 사용하여 특정 유형의 첫 번째 항목을 찾았지만 해당 유형의 모든 객체를 찾도록 쉽게 수정할 수 있습니다.
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;
}
VisualTreeHelper.GetChildrenCount(depObj);
위의 여러 예제에서 사용 된 행 은 GroupBox
es에 대해 0이 아닌 카운트를 반환하지 않는 것으로 나타났습니다 . 특히 GroupBox
contains 포함 Grid
및 Grid
contains 하위 요소가 있습니다. 나는 이것이 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;
}
}
}
}
특정 유형의 모든 자식 목록을 얻으려면 다음을 사용할 수 있습니다.
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;
}
예를 들어 탭 컨트롤의 자식 탭 컨트롤을 찾을 수 있도록 재귀를 약간 변경합니다.
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;
}
제네릭 구문을 사용하는 또 다른 컴팩트 버전이 있습니다.
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;
}
}
그리고 이것이 위로 작동하는 방식입니다
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);
}
}
}
}
VisualTreeHelper 사용은 Visual 또는 Visual3D에서 파생 된 컨트롤에서만 작동합니다. 다른 요소 (예 : TextBlock, FlowDocument 등)도 검사해야하는 경우 VisualTreeHelper를 사용하면 예외가 발생합니다.
필요한 경우 논리 트리로 대체되는 대안이 있습니다.
http://www.hardcodet.net/2009/06/finding-elements-in-wpf-tree-both-ways
의견을 추가하고 싶었지만 50pt 미만으로 "답변"만 할 수 있습니다. "VisualTreeHelper"메서드를 사용하여 XAML "TextBlock"개체를 검색하면 XAML "Button"개체도 가져옵니다. Textblock.Text 매개 변수에 기록하여 "TextBlock"개체를 다시 초기화하면 더 이상 Button.Content 매개 변수를 사용하여 Button 텍스트를 변경할 수 없습니다. 버튼은 Textblock에서 작성된 텍스트를 영구적으로 표시합니다.
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 "TextBox"를 사용하고 XAMAL 버튼을 모방하는 메서드 (또는 이벤트)를 추가하십시오. "TextBlock"을 검색하면 XAML "TextBox"가 수집되지 않습니다.
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;
};
어떤 이유로 든 여기에 게시 된 답변 중 어느 것도 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);
}
}
}
}
도움이 되길 바랍니다.
허용 응답 반환 발견 된 요소가 더 많거나 적은 순서가 되돌아와 아직 분석 나뭇 가지의 단계를 반복하기 전에, 그 길을 따라 발견 된 요소를 산출하면서, 가능한 한 깊이로 첫 번째 자식 분기를 따라.
하위 요소가 내림차순으로 필요한 경우 직접 하위가 먼저 생성 되고 하위 하위 가 생성되면 다음 알고리즘이 작동합니다.
public static IEnumerable<T> GetVisualDescendants<T>(DependencyObject parent, bool applyTemplates = false)
where T : DependencyObject
{
if (parent == null || !(child is Visual || child is Visual3D))
yield break;
var descendants = new Queue<DependencyObject>();
descendants.Enqueue(parent);
while (descendants.Count > 0)
{
var currentDescendant = descendants.Dequeue();
if (applyTemplates)
(currentDescendant as FrameworkElement)?.ApplyTemplate();
for (var i = 0; i < VisualTreeHelper.GetChildrenCount(currentDescendant); i++)
{
var child = VisualTreeHelper.GetChild(currentDescendant, i);
if (child is Visual || child is Visual3D)
descendants.Enqueue(child);
if (child is T foundObject)
yield return foundObject;
}
}
}
결과 요소는 가장 가까운 것부터 가장 먼 것까지 주문됩니다. 예를 들어 어떤 유형과 조건에서 가장 가까운 자식 요소를 찾는 경우에 유용합니다.
var foundElement = GetDescendants<StackPanel>(someElement)
.FirstOrDefault(o => o.SomeProperty == SomeState);
child
정의되지 않았습니다.
@Bryce, 정말 좋은 답변입니다.
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