๐ WPF TreeView ๋ ธ๋ ๊ฒ์ ๊ธฐ๋ฅ ๊ตฌํํ๊ธฐ
์ด๋ฒ ํฌ์คํธ์์๋ WPF์ TreeView์์ ๋
ธ๋ ๊ฒ์ ๊ธฐ๋ฅ์ MVVM ํจํด์ผ๋ก ๊ตฌํํด๋ด
๋๋ค.
์ฌ์ฉ์๊ฐ ์
๋ ฅํ ๊ฒ์์ด์ ๋ฐ๋ผ ํน์ ๋
ธ๋๋ง ํ์ํ๊ฑฐ๋ ๊ฐ์กฐํ๋ ๋ฐฉ์์ผ๋ก UX๋ฅผ ๊ฐ์ ํ ์ ์์ต๋๋ค.
๋ชฉ์ฐจ
1. Category ๋ชจ๋ธ ํด๋์ค
public class Category : INotifyPropertyChanged
{
public string Name { get; set; }
public ObservableCollection<Category> Children { get; set; } = new();
private bool _isVisible = true;
public bool IsVisible
{
get => _isVisible;
set { _isVisible = value; OnPropertyChanged(nameof(IsVisible)); }
}
public event PropertyChangedEventHandler? PropertyChanged;
protected void OnPropertyChanged(string propertyName)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
2. ViewModel ๊ตฌ์ฑ ๋ฐ ๊ฒ์ ๋ก์ง
public class MainViewModel : INotifyPropertyChanged
{
public ObservableCollection<Category> Categories { get; set; }
private string _searchText = string.Empty;
public string SearchText
{
get => _searchText;
set
{
_searchText = value;
OnPropertyChanged(nameof(SearchText));
ApplySearch();
}
}
public MainViewModel()
{
Categories = new ObservableCollection<Category>
{
new Category
{
Name = "ํ๋ก๊ทธ๋๋ฐ",
Children = new ObservableCollection<Category>
{
new Category { Name = "C#" },
new Category { Name = "Java" },
new Category { Name = "Python" }
}
},
new Category
{
Name = "๋ฐ์ดํฐ๋ฒ ์ด์ค",
Children = new ObservableCollection<Category>
{
new Category { Name = "Oracle" },
new Category { Name = "MySQL" },
new Category { Name = "PostgreSQL" }
}
}
};
}
private void ApplySearch()
{
foreach (var category in Categories)
{
FilterCategory(category, SearchText);
}
}
private bool FilterCategory(Category category, string search)
{
bool match = category.Name.Contains(search, StringComparison.OrdinalIgnoreCase);
bool childMatch = false;
foreach (var child in category.Children)
{
childMatch |= FilterCategory(child, search);
}
category.IsVisible = match || childMatch;
return category.IsVisible;
}
public event PropertyChangedEventHandler? PropertyChanged;
protected void OnPropertyChanged(string propertyName)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
3. XAML์์ ๊ฒ์ UI ๋ฐ ๋ฐ์ธ๋ฉ
<StackPanel Margin="10">
<TextBox Width="300" Margin="0,0,0,10"
Text="{Binding SearchText, UpdateSourceTrigger=PropertyChanged}"
PlaceholderText="๋
ธ๋ ๊ฒ์..." />
<TreeView ItemsSource="{Binding Categories}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="Visibility" Value="{Binding IsVisible, Converter={StaticResource BoolToVisibilityConverter}}" />
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
</StackPanel>
๐ BoolToVisibilityConverter ์ถ๊ฐ
public class BoolToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (bool)value ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
4. ํํฐ๋ง ๋ฐ ๊ฐ์กฐ ๋ก์ง ์ค๋ช
- SearchText ํ๋กํผํฐ ๋ณ๊ฒฝ ์ ํํฐ๋ง ๋์
- ๋
ธ๋ ์ด๋ฆ์ด ๊ฒ์์ด๋ฅผ ํฌํจํ๊ฑฐ๋ ์์ ์ค ํฌํจ๋ ๋
ธ๋๊ฐ ์๋ค๋ฉด
IsVisible = true
- TreeViewItem์
Visibility
์์ฑ์ผ๋ก ํํฐ๋ง ์ ์ฉ
5. ๋ง๋ฌด๋ฆฌ ๋ฐ ๋ค์ ํธ ์๊ณ
TreeView์ ๊ฒ์ ๊ธฐ๋ฅ์ ๊ณ์ธตํ ๋ฐ์ดํฐ๋ฅผ ๋น ๋ฅด๊ฒ ํ์ํ ์ ์๋๋ก ๋์์ค๋๋ค.
MVVM ๊ตฌ์กฐ๋ฅผ ํ์ฉํ๋ฉด ์ ์ฐํ๊ณ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ UI๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค.
- ๊ฒ์ ๊ธฐ๋ฅ์ ์ฌ์ฉ์ ์ ๋ ฅ ์ฆ์ ๋ฐ์
- ์์ ๋ ธ๋ ์ฌ๊ท ํ์์ผ๋ก ์ ์ฒด ํธ๋ฆฌ์์ ๊ฒ์ ๊ฐ๋ฅ
- ๊ฐ๋จํ Visibility ์ปจํธ๋กค๋ก UX ๊ฐ์
๋ค์ ํธ์์๋ TreeView ๋
ธ๋ ์ ํ ์ํ ์ ์ง ๋ฐ ๋ณต์ ๊ธฐ๋ฅ์ ๊ตฌํํด๋ณด๊ฒ ์ต๋๋ค! ๐
๋ฐ์ดํฐ ์ ์ฅ ๋ฐ ๋ค์ ๋ถ๋ฌ์ฌ ๋ ์ ํ ์ํ๋ฅผ ์ ์งํ๋ ๊ฒ๋ ์ฌ์ฉ์ ํธ์์ฑ์ ํฐ ๋์์ด ๋ฉ๋๋ค.
'C#' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
WPF TreeView ๋๋๊ทธ ์ค ๋๋กญ ๊ธฐ๋ฅ ๊ตฌํ (0) | 2025.04.14 |
---|---|
WPF TreeView ์ ํ ์ํ ์ ์ฅ ๋ฐ ๋ณต์ (0) | 2025.04.13 |
WPF TreeView ์ฒดํฌ๋ฐ์ค ๋ ธ๋ ๊ตฌํ (0) | 2025.04.11 |
WPF TreeView Drag & Drop ๊ตฌํ (0) | 2025.04.10 |
WPF TreeView ContextMenu ๋ ธ๋ ์ถ๊ฐ/์ญ์ (0) | 2025.04.10 |