본문 바로가기
프로그래밍 언어/WPF

[C#] WPF - UI의 모든 컨트롤 가져오기

by Jinwood 2024. 1. 5.
반응형

1. 개요

 

Winform/WPF 사용하다보면 UI 값을 특정 파일에 저장해 두거나,

이후 UI Load UI 내부 컨트롤에 필요한 값을 설정하는 작업이 필요할 때가 있다.

이를 위해서 WPF UI 내부의 모든 컨트롤을 가져오거나, 사용자가 선택한 타입의 컨트롤만 가져오는 메서드가 필요하다.

 

Winform에서 UI 내부 컨트롤 사용자가 설정한 컨트롤의 리스트를 가져오는 방법은 예전 글로 작성한 있다.

 

https://hvyair.tistory.com/49

 

[C#] WinForm 의 모든 컨트롤 가져오기

특정 Form의 Control을 가져오려는 경우 Linq의 Cast를 사용하면 된다. 아래는 모든 컨트롤 정보를 리스트로 정의하는 코드이다. 1 2 3 // Control를 가져오려는 Form의 이름 : myForm Form myForm; List Control_List =

hvyair.tistory.com

 

WPF에서는 UI 내부 컨트롤을 가져오는 방법으로 VisualTreeHelper 이용한 방법과 LogicalTreeHelper 이용한 방법이 있다. 방법의 사용법은 유사하지만, 현재까지 사용해본 결과 LogicalTreeHelper 이용한 방법이 나은 같다. 각각의 방식에 대한 설명과 차이점은 아래와 같다.

 

2. VisualTreeHelper를 이용한 방법

VisualTreeHelper GetChild 메서드를 통해 DependencyObject 가져오고, 내부의 foreach 반복문으로 계속 자식 컨트롤을 찾아낸다. 아래 메서드 및 사용 예를 작성하였다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using System.Collections.Generic;
using System.Windows.Controls;
using System.Window;
 
 
public static IEnumerable<T> FindWindowChildren<T>(DependencyObject dObj) where T : DependencyObject
{
    if (dObj != null)
    {
        for (int i = 0; i < System.Windows.Media.VisualTreeHelper.GetChildrenCount(dObj); i++)
        {
            DependencyObject ch = System.Windows.Media.VisualTreeHelper.GetChild(dObj, i);
            if (ch != null && ch is T)
            {
                yield return (T)ch;
            }
            foreach (T nestedChild in FindWindowChildren<T>(ch))
            {
                yield return nestedChild;
            }
        }
    }
}
cs

 

코드 사용 예

1
IEnumerable<TextBox> textboxList = FindWindowChildren<TextBox>(form);
cs

 

3. LogicalTreeHelper를 이용한 방법

VisualTreeHelper 마찬가지로 GetChildren 메서드를 통해 자식 컨트롤을 찾고, 재귀함수로 계속해서 찾아나가는 방식이다. LogicalTreeHelper에서 IEnumerable System.Collections로부터 가져오는 것이므로 using문을 주의해야하고, 반드시 정적(static) 클래스에서 사용해야한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
using System.Collections;
using System.Windows.Controls;
using System.Window;
 
public static class Get_WPF_Control
{
    public static List<T> GetLogicalChildCollection<T>(this DependencyObject parent) where T : DependencyObject
    {
        List<T> logicalCollection = new List<T>();
        GetLogicalChildCollection(parent, logicalCollection);
        return logicalCollection;
    }
 
    private static void GetLogicalChildCollection<T>(DependencyObject parent, List<T> logicalCollection) where T : DependencyObject
    {
        IEnumerable children = LogicalTreeHelper.GetChildren(parent);
        foreach (object child in children)
        {
            if (child is DependencyObject)
            {
                DependencyObject depChild = child as DependencyObject;
                if (child is T)
                {
                    logicalCollection.Add(child as T);
                }
                GetLogicalChildCollection(depChild, logicalCollection);
            }
        }
    }
}
cs

 

코드 사용 예

1
List<TextBox> textboxList = Get_WPF_Control.GetLogicalChildCollection<TextBox>(form);
cs

 

4. 차이점

VisualTreeHelper 이용한 방법과 LogicalTreeHelper 이용한 방법 둘다 사용 방식은 유사해 보이지만, 실제로 동작해보면 차이점을 있다.

  1. VisualTreeHelper 이용한 방법은 현재 UI에서 보이는 컨트롤의 정보만 가져올 있다.
    예를
    들어 Expander 접힌 상태(IsExpanded = False)라면 Expander 내부의 컨트롤은 가져올 없다.
  2. LogicalTreeHelper 이용한 방법은 현재 UI에서 보이지 않는 컨트롤의 정보까지 가져올 있다.
    위의
    예시에서 Expander 접힌 상태여도 Expander 내부의 컨트롤을 가져올 있다.

 

5. 결론

추후 사용 LogicalTreeHelper 사용한 방법에 문제가 없다면 VisualTreeHelper보다는 LogicalTreeHelper 사용한 방법으로 모든 UI 내부의 WPF 컨트롤을 가져오는 방법이 낫다.

반응형

댓글