트리뷰 구현에 대해서 여쭤봅니다

대쉬보드에 메뉴를 한번 만들어보려고 WPF로 트리뷰를 구현 해보고 있습니다.

현재 데이터를 만들어 화면에 출력하고 디자인 커스텀, 동작하는거 까지 완료하였습니다

public class MainDashboardPageViewModel : ViewModelBase
{
    public ObservableCollection<TreeItem> Items { get; set; } = new ObservableCollection<TreeItem>();

    public MainDashboardPageViewModel()
    {
        var treeItems = new TreeItem { Key = "1", Parent = "0", Text = "1단지", Node = 1, Select = "N" };
        treeItems.Children.Add(new TreeItem { Key = "1-1", Parent = "1", Text = "사과", Node = 2, Select = "N" });
        treeItems.Children.Add(new TreeItem { Key = "1-2", Parent = "1", Text = "바나나", Node = 2, Select = "N" });
        treeItems.Children.Add(new TreeItem { Key = "1-3", Parent = "1", Text = "파인애플", Node = 2, Select = "N" });

        var treeItems2 = new TreeItem { Key = "2", Parent = "0", Text = "2단지", Node = 1, Select = "Y" };
        treeItems2.Children.Add(new TreeItem { Key = "2-1", Parent = "2", Text = "휴대폰", Node = 2, Select = "N" });
        treeItems2.Children.Add(new TreeItem { Key = "2-2", Parent = "2", Text = "컴퓨터", Node = 2, Select = "Y" });

        Items.Add(treeItems);
        Items.Add(treeItems2);

    }
}

메뉴와 하위 메뉴를 Node 1, 2로 구분하였고 Select YN을 통해 선택되는 이벤트를 구현하였습니다.

만들다보니 다른 아이템을 클릭 하였을때 기존에 Select=“Y” 를 N으로 변경하고 처리하는게

너무 수동적이다라는 생각이들었습니다.

검색을해보니 체크기능을 사용하기도하고 토글버튼을 사용을 하기도하고 다양하더라구요

어떤 방법이 가장 효과적인지 경험담좀 알려주시면 감사하겠습니다.

추가로 제가 공부하면서 만드는 트리뷰인데 검토가 가능하시면 조언좀 부탁드리겠습니다.

1 Like

안녕하세요
@b21 님께서 하신 방법을 최대한 살려가면서 다시 한번만들어봤습니다.

아마 토글버튼의 IsToggle을 통해 IsExpanded와 동일한 기능을 표현한 기본 템플릿을 보신거같네요

TreeviewItem을 사용 목적은 IsExpanded를 응용하시면
Select는 사용하지 않도 충분히 구현이 가능합니다.

TreeviewItem의 노드의 노드, 즉 꼬리에 꼬리를 걸어 List형태로 만들어낼수 있기 때문에
그것을 캐치하여 응용해보시면됩니다.
b21님께서 만드신 코드를 응용해서 만든 방법을 공유드립니다!

보시고 댓글로 질문남겨주세요!

<Page
    x:Class="MVVM.view.MainDashboardPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:cv="clr-namespace:MVVM.module"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:vm="clr-namespace:MVVM.viewmodel"
    d:DesignHeight="980"
    d:DesignWidth="1920"
    FontFamily="Pretendard Regular"
    mc:Ignorable="d">
    <Page.DataContext>
        <vm:MainDashboardPageViewModel />
    </Page.DataContext>

    <Page.Resources>
        <Style x:Key="TabStyle" TargetType="{x:Type TextBlock}">
            <Setter Property="VerticalAlignment" Value="Center" />
            <Setter Property="Background" Value="Transparent" />
            <Setter Property="Text" Value="{Binding Text}" />
            <Setter Property="Foreground" Value="#C9D0EA" />
            <Setter Property="Cursor" Value="Hand" />
            <Setter Property="FontSize" Value="18" />
            <Setter Property="FontFamily" Value="{StaticResource PretendardMedium}" />
            <Setter Property="Padding" Value="0,15" />
        </Style>
        <cv:TreeItemConverter x:Key="treeItemConverter" />

        <ControlTemplate x:Key="ChildrenStyle" TargetType="{x:Type TreeViewItem}">
            <StackPanel Orientation="Vertical" ScrollViewer.HorizontalScrollBarVisibility="Hidden">
                <StackPanel Orientation="Horizontal">
                    <Ellipse
                        x:Name="PART_Elipse"
                        Width="5"
                        Height="5"
                        Margin="0,0,10,0"
                        HorizontalAlignment="Left"
                        VerticalAlignment="Center"
                        Fill="#ffffff" />
                    <TextBlock
                        x:Name="PART_Title"
                        Padding="0,8"
                        FontFamily="{StaticResource PretendardRegular}"
                        FontSize="16"
                        Foreground="#FFFFFF"
                        Style="{StaticResource TabStyle}" />
                </StackPanel>
                <ItemsPresenter />
            </StackPanel>
            <ControlTemplate.Triggers>
                <Trigger Property="IsExpanded" Value="True">
                    <Setter TargetName="PART_Title" Property="Foreground" Value="#02D48F" />
                    <Setter TargetName="PART_Title" Property="FontFamily" Value="{StaticResource PretendardMedium}" />
                    <Setter TargetName="PART_Elipse" Property="Fill" Value="#02D48F" />
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>

        <ControlTemplate x:Key="ParentStyle" TargetType="{x:Type TreeViewItem}">
            <StackPanel Background="Transparent" ScrollViewer.HorizontalScrollBarVisibility="Hidden">
                <Grid x:Name="PART_AREA">
                    <TextBlock
                        x:Name="PART_Title"
                        HorizontalAlignment="Left"
                        Style="{StaticResource TabStyle}" />
                    <Image
                        x:Name="PART_icon"
                        Width="15"
                        HorizontalAlignment="Right"
                        VerticalAlignment="Center"
                        Source="/image/icon/plus.png" />
                </Grid>
                <Line
                    x:Name="PART_Line"
                    HorizontalAlignment="Left"
                    VerticalAlignment="Bottom"
                    Stroke="#26FFFFFF"
                    StrokeThickness="1"
                    X1="0"
                    X2="{Binding ElementName=PART_AREA, Path=ActualWidth}"
                    Y1="0"
                    Y2="0" />
                <TreeView
                    x:Name="PART_Children"
                    Background="Transparent"
                    BorderBrush="{x:Null}"
                    ItemsSource="{Binding Children}"
                    Visibility="Collapsed">
                    <TreeView.ItemContainerStyle>
                        <Style TargetType="{x:Type TreeViewItem}">
                            <Setter Property="Template" Value="{StaticResource ChildrenStyle}" />
                        </Style>
                    </TreeView.ItemContainerStyle>
                </TreeView>
            </StackPanel>
            <ControlTemplate.Triggers>
                <Trigger Property="IsExpanded" Value="True">
                    <Setter TargetName="PART_AREA" Property="Margin" Value="0,0,0,0" />
                    <Setter TargetName="PART_Title" Property="Foreground" Value="#FFFFFF" />
                    <Setter TargetName="PART_Title" Property="FontFamily" Value="{StaticResource PretendardSemiBold}" />
                    <Setter TargetName="PART_icon" Property="Source" Value="/MVVM;Component/image/icon/minus.png" />
                    <Setter TargetName="PART_Children" Property="Visibility" Value="Visible" />
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </Page.Resources>
    <Grid Background="#FF15151F">
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="10" />
        </Grid.RowDefinitions>
        <Grid Grid.Row="0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="10" />
                <ColumnDefinition Width="360" />
                <ColumnDefinition Width="10" />
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="10" />
                <ColumnDefinition Width="360" />
                <ColumnDefinition Width="10" />
            </Grid.ColumnDefinitions>
            <!--  Start  -->
            <Grid Grid.Column="1">
                <TreeView
                    VerticalAlignment="Top"
                    Background="{x:Null}"
                    BorderBrush="{x:Null}"
                    BorderThickness="0"
                    ItemsSource="{Binding Items}"
                    ScrollViewer.HorizontalScrollBarVisibility="Hidden"
                    ScrollViewer.VerticalScrollBarVisibility="Auto">
                    <TreeView.ItemContainerStyle>
                        <Style TargetType="{x:Type TreeViewItem}">
                            <Setter Property="Template" Value="{StaticResource ParentStyle}" />
                        </Style>
                    </TreeView.ItemContainerStyle>
                </TreeView>
            </Grid>
        </Grid>
    </Grid>
</Page>
3 Likes

감사합니다.
보내주신 코드 응용해서 해보고 궁금한거 질문드리겠습니다.
신경 써주셔서 감사합니다.

1 Like

소스 적용해서 이것저것 수정도해보고 테스트도 해봤습니다.

지금 하고싶은게 하위메뉴를 선택하면 이미선택되어있는데 메뉴의 색상을 복구 시키고싶습니다.

메뉴를 하나만 선택하게 하는거죠.

과거 소스에서는 Select라는 값을 가지고 데이터를 변환하려고하였지만

이것 또한 속성 또는 이벤트로 처리 할 수 있을거같은데

어떤것을 이용해야할지 알려주실수 있으실까요?

1 Like

ParentStyle

  • Treeview 대신 ListBox로 변경하시고
  • TreeVIew ItemsContainerStyle에 ListBoxItem으로 변경

ChildeStyle

  • TargetType를 TreeviewItem 대신 ListBoxItem으로 변경
  • Trigger의 IsExpanded 대신 IsSelected로 변경

위 처럼 구현하실 경우엔 Select라는 역할은 신경안쓰셔도됩니다!

Screenshot 2024-01-05 at 11.33.38
만일 Parent들간의 Childern select가 필요하시다면은 필요하실꺼같네요!

2 Likes

말씀해주신것처럼 해봤는데 저는 현재 1단지를 누르고 사과를 누른상태에서 2단지를 누르면 1단지가 접어집니다

2단지에서 휴대폰을 누르고 1단지를 누르면 2단지가 접어지면서 전에 누를 사과가 선택되어있더라구요

1단지 사과 클릭 후

2단지 휴대폰 클릭 시 사과도 선택 해제 하고싶은데

클릭할때 데이터 초기화를 시키면 되는걸까요?

클릭하시는 이벤트를 따로 받아오시진 못하실겁니다.
별도로 커맨드 이벤트를 발생시키신다던가
IsSelcted의 값을 바인딩하셔서

만드신 이벤트를 통해서 기존의 Selected 된 데이터를 true에서 false로 변경하시면됩니다!

1 Like

이렇게 저렇게 막 해보고 있는데 어렵네요…

도움주셔서 감사합니다. 열심히 헤딩해보겠습니다.

1 Like

모델에 추가한 Select 기본값 false로 주고

isSelected에 바인딩 후

클릭이벤트 발생할때 CS에서 해당 true로 변경 및 나머지 false 처리

부모메뉴도 동일하게 해서 이벤트 처리 했습니다.

도움주신 ControlTemplate 이용해서 비슷하게 단일 메뉴도 구성 해봤고

이것저것 해보고있네요.

도움주셔서 감사합니다. 잘배웠습니다.

2 Likes