본문 바로가기

C#의 속삭임

[C#][WPF][MVVM]TreeView

* 트리뷰를 MVVM구조로 만들까 한다. 각 구조별로 코딩된 소스를 기재 할까 한다.




* Model [지금 구현하고 하는 것에는 Model이 꼭 필요한것은 아니다.]

* ServerInfoService.cs

class ServerInfoService : IServerInfoService

    {


        private ServerInfoItem item = new ServerInfoItem("", "");//Item을 옮길녀석


        public void GetServerTree(Action<ServerInfoItem, Exception> callback)

        {

            

            List<ServerInfoItem> ItemList = new List<ServerInfoItem>();

            //루트 입력 테스트

            item.ItemList.Add(new ServerInfoItem("전체서버", ""));


            //자식들 입력 테스트값

            item.ItemList[0].ItemList.Add(new ServerInfoItem("Host1", "192.168.10.200"));

            item.ItemList[0].ItemList.Add(new ServerInfoItem("Host2", "lab.onenetview.co.kr"));

            item.ItemList[0].ItemList.Add(new ServerInfoItem("Host3", "127.0.0.1"));

            item.ItemList[0].ItemList.Add(new ServerInfoItem("Host4", "172.200.100.100"));

            item.ItemList[0].ItemList.Add(new ServerInfoItem("Host5", "172.200.100.101"));

            item.ItemList[0].ItemList.Add(new ServerInfoItem("Host6", "172.200.100.102"));

            item.ItemList[0].ItemList.Add(new ServerInfoItem("Host7", "172.200.100.103"));


            item.ItemList[0].ItemList[6].ItemList.Add(new ServerInfoItem("Host7-1", "172.200.100.104"));

            item.ItemList[0].ItemList[6].ItemList.Add(new ServerInfoItem("Host7-2", "172.200.100.105"));


            Console.WriteLine("Call back!!");


            callback(item, null);

            

        }

    }



* ServerInfoItem.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;


namespace avanceCMS45.Model.serverlist

{

    public class ServerInfoItem

    {

        

        public ServerInfoItem( string name, string ip )

        {


            this.ItemList = new List<ServerInfoItem>();

            this.name = name;

            this.ip = ip;

            


        }


        public List<ServerInfoItem> ItemList 

        {

            get;

            private set;

        }


        public string name

        {

            get;

            private set;

        }


        public string ip

        {

            get;

            private set;

        }


    }

}






* View 

** View 화면의 트리를 유저 컨트롤러로 했지만 구지 그렇게 할필요는 없다.

<UserControl x:Class="*******.View.serverlist.ServerTreeView"

             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 

             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 

             xmlns:data="clr-namespace:*******.Model.serverlist" 

             xmlns:viewmodel="clr-namespace:*********.ViewModel.serverlist" 

             xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

             xmlns:Command="http://www.galasoft.ch/mvvmlight"

             DataContext="{Binding Source={StaticResource ServerTreeLocator}, Path=ServerTreeViewModel}"

             mc:Ignorable="d" 

             d:DesignHeight="900" d:DesignWidth="300">

    <Grid>

        <TreeView HorizontalAlignment="Left" Height="900" VerticalAlignment="Top" Width="300" ItemsSource="{Binding firstGeneration}" Background="#FF1A1A1A" Foreground="Black" FontSize="16" FontWeight="Bold" BorderBrush="Black" BorderThickness="0" >

            <TreeView.Resources>

                <Style TargetType="{x:Type TreeViewItem}">

                    <Setter Property="Foreground" Value="#FF44B6F8"/>

                    <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />

                    <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />

                    <Setter Property="FontWeight" Value="Normal" />

                    <Style.Triggers>

                        <Trigger Property="IsSelected" Value="True">

                            <Setter Property="FontWeight" Value="Bold" />

                        </Trigger>

                    </Style.Triggers>

                </Style>

            </TreeView.Resources>

            <TreeView.ItemTemplate>

                <HierarchicalDataTemplate ItemsSource="{Binding Children}">

                    <StackPanel Orientation="Horizontal">

                        <Image Width="16" Height="16" Margin="3,0" Source="../dashboard/images/primaryMark.png" />

                        <TextBlock Text="{Binding name}" />

                    </StackPanel>

                </HierarchicalDataTemplate>

            </TreeView.ItemTemplate>

        </TreeView>

    </Grid>

</UserControl>





* ViewModel

** 가장 중요한 ViewModel 

** ViewModel은 두개가 필요하다. 하나는 트리 자체를 위한것이고, 또하나는 트리 내부의 하나하나의 노드를 위한 것이다.

** 소스를 보고 반드시 이해를 해야지, 다른 데이타 그리드라든지 그런것들을 다룰때 편하다. 왜냐면 기본 개념이 비슷비슷하기 때문이다.

* ServerTreeViewModel.cs [트리 자체를 위한 뷰모델이다.]

public class ServerTreeViewModel : ViewModelBase

    {

        private readonly IServerInfoService serverInfoService;

        private ReadOnlyCollection<ServerItemViewModel> _firstGeneration;

        private List<ServerInfoItem> _ItemList;

        private ServerItemViewModel _rootServer;


        public ServerTreeViewModel(IServerInfoService serverInfoService)

        {


            this.serverInfoService = serverInfoService;

            this.serverInfoService.GetServerTree(

                (item, error) =>

                {

                    if (error != null)

                    {

                        // Report error here

                        return;

                    }


                    ItemList = item.ItemList;

                    _rootServer = new ServerItemViewModel(ItemList[0]);

                    _firstGeneration = new ReadOnlyCollection<ServerItemViewModel>(

                        new ServerItemViewModel[] 

                        { 

                            _rootServer 

                        });

                });


        }


        public List<ServerInfoItem> ItemList

        {

            get { return _ItemList; }

            set

            {

                _ItemList = value;

                RaisePropertyChanged("ItemList");

            }

        }


        public ReadOnlyCollection<ServerItemViewModel> firstGeneration {

            get { return _firstGeneration; }

            set { 

                _firstGeneration = value;

                RaisePropertyChanged("firstGeneration");

            }

        }


      


    }


* ServerItemViewModel.cs [각 노드를 위한 뷰모델이다.]

public class ServerItemViewModel : ViewModelBase

    {


        private RelayCommand<string> _OnSelectServer;

        private ServerInfoItem serverInfo;

        private string _name;

        private string _ip;

        private ServerItemViewModel parent;

        private ReadOnlyCollection<ServerItemViewModel> _children;

        private bool _isExpanded;

        private bool _isSelected;

        private string oldSelected;


        public ServerItemViewModel(ServerInfoItem serverInfo)

            : this(serverInfo, null)

        {

        }


        public ServerItemViewModel( ServerInfoItem serverInfo, ServerItemViewModel parent )

        {

            this.serverInfo = serverInfo;

            this.parent = parent;


            _ip = serverInfo.ip;

            _name = serverInfo.name;


            _children = new ReadOnlyCollection<ServerItemViewModel>(

            (from child in serverInfo.ItemList

             select new ServerItemViewModel(child, this))

             .ToList<ServerItemViewModel>());

        }


        public ReadOnlyCollection<ServerItemViewModel> Children

        {

            get { return _children; }

        }


        public RelayCommand<string> OnSelectServerEvent

        {

            get

            {

                if (_OnSelectServer == null)

                {

                    _OnSelectServer = new RelayCommand<string>(arg => OnSelectServer(arg));

                }

                return _OnSelectServer;

            }

        }

        private void OnSelectServer(string key)

        {


            MessageBox.Show(key);


        }


        public string name

        {


            get { return _name; }

            set

            {

                _name = value;

                RaisePropertyChanged("name");


            }

        }


        public string ip

        {


            get { return _ip; }

            set

            {

                _ip = value;

                RaisePropertyChanged("ip");


            }

        }


        public bool IsExpanded

        {

            get { return _isExpanded; }

            set

            {

                if (value != _isExpanded)

                {

                    _isExpanded = value;

                    RaisePropertyChanged("IsExpanded");

                }


                // Expand all the way up to the root.

                if (_isExpanded && parent != null)

                    parent.IsExpanded = true;

            }

        }


        public bool IsSelected

        {

            get { return _isSelected; }

            set

            {

                if (value != _isSelected)

                {

                    _isSelected = value;

                    if ( oldSelected != name )

                    {

                        oldSelected = name;

                    }

                    RaisePropertyChanged("IsSelected");

                    

                }

            }

        }


    }