ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • WPF MVVM 패턴을 이용한 To Do List 만들기
    프로그래밍/C# 2021. 11. 27. 20:51
    반응형

    안녕하세요 까치 입니다. 오랜만에 글을 쓰는 것 같습니다.

    요즘 회사일에 지쳐 공부를 뒷전으로 미루고 있었는데 

    이제는 공부를 해야 할것같아 WPF를 익숙하게 다룰수 있도록 공부를 하고 있습니다.

    그런김에 ToDoList 를 MVVM패턴을 이용해 한번 만들어봤습니다.

     

    바로 살펴보도록 하죠 

    일단 완성된 화면은 이렇게 되었습니다.

     

    일단 화면 전체를 grid row속성을 이용하여 3등분 하였습니다.

    First Row - 일정을 model에서 불러오는 기능을 넣었습니다.

    Second Row - ScrollViewer를 이용하여 리스트를 스크롤 단위로 살필수 있도록 하였습니다.

    Third row - 일정 제목을 넣을

    제목과 일정 등록을 할 수 있는 내용을 넣었습니다.

    <Window x:Class="WPFTODOLIST.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WPFTODOLIST"
            xmlns:viewModel="clr-namespace:WPFTODOLIST.ViewModels"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="800">
        <Window.DataContext>
            <viewModel:TaskListViewModel/>
        </Window.DataContext>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="auto"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="auto"/>
            </Grid.RowDefinitions>
            
            <Grid Grid.Row="0">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="4*"/>
                    <ColumnDefinition Width="*" MinWidth="80"/>
                </Grid.ColumnDefinitions>
                <TextBlock Text="TO DO LIST"/>
                <Button Grid.Column="1" Content="일정 불러오기" Command="{Binding ReadTaskCommand}" />
            </Grid>
    
            <ScrollViewer Grid.Row="1">
                <ItemsControl  x:Name="list" ItemsSource="{Binding Tasks}">
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate >
                            <StackPanel Orientation="Vertical"/>
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
    
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <Grid>
                                <Grid.ColumnDefinitions >
                                    <ColumnDefinition Width="*"/>
                                    <ColumnDefinition Width="auto"/>
                                </Grid.ColumnDefinitions>
                                <TextBlock Text="{Binding Name}" Grid.Column="0"/>
                                <CheckBox  IsChecked="{Binding Complete}" Grid.Column="1"/>
                            </Grid>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>
            </ScrollViewer>
    
            <Grid Grid.Row="2">
                <Grid.ColumnDefinitions >
                    <ColumnDefinition Width="4*"/>
                    <ColumnDefinition Width="*" MinWidth="80"/>
                </Grid.ColumnDefinitions>
    
                <TextBox Text="{Binding TaskName, UpdateSourceTrigger=PropertyChanged}"/>
                <Button Grid.Column="1" Content="일정 등록" Command="{Binding CreateTaskCommand}" />
            </Grid>
        </Grid>
    </Window>

    그리고 중요하게 봐야 할게 첫번째 와 세번째 버튼을 넣었는데 이부분에 Create와 Read 커멘드를 넣었습니다.

    이부분은 가운데 바인딩 되어있는 Task에 값을 변경해줄 커멘드를 호출해줄 녀석입니다.

     

    또한 두번째 로우에 Task를 바인딩하여 값을 변경하는데 자동으로 viewmodel을 적용하게 만들었습니다.

    ItemsControl에 대한 내용은 좀 중요하니 먼저 공부를 하시고 와서 

    소스를 봐주시는걸 추천 드립니다.

     

    저는 ItemsControl 속성인 paneltemplate을 vertical로 하여 수직으로 리스트가 표현 되도록 하였습니다.

    그리고 그 수직으로 싸이는 내용을 ItemTemplate 을 이용하여 2등분 한 후 textblock(레이블) 체크박스를 넣었습니다.

     

     

    그다음 ViewMolel ListViewModel을 구성했습니다.

    namespace WPFTODOLIST.ViewModels
    {
        public class TaskViewModel : Notifier 
        {
            private string _name;
            public string Name
            {
                get { return _name; }
                set
                {
                    _name = value;
                    OnPropertyChanged(nameof(Name));
                }
            }
            private bool _complete;
            public bool Complete
            {
                get { return _complete; }
                set
                {
                    _complete = value;
                    OnPropertyChanged(nameof(Complete));
                }
            }
    
    
        }
    }
    namespace WPFTODOLIST.ViewModels
    {
        public class TaskListViewModel : Notifier 
        {
            private ObservableCollection<TaskViewModel> _tasks;
    
            public ObservableCollection<TaskViewModel> Tasks
            {
                get { return _tasks; }
                set
                {
                    _tasks = value;
                    OnPropertyChanged(nameof(Tasks));
                }
            }
            private string _taskName;
            public string TaskName
            {
                get { return _taskName; }
                set
                {
                    _taskName = value;
                    OnPropertyChanged(nameof(TaskName));
                }
            }
    
            private ICommand createTaskCommand;
            public ICommand CreateTaskCommand
            {
                get{ return (this.createTaskCommand) ?? (this.createTaskCommand = new DelegateCommand(Create)); }
            }
            private void Create()
            {
                Tasks.Add(new TaskViewModel() { Name = TaskName, Complete = false });
            }
    
            private ICommand readTaskCommand;
            public ICommand ReadTaskCommand
            {
                get { return (this.readTaskCommand) ?? (this.readTaskCommand = new DelegateCommand(Read)); }
            }
            Models.TaskModel test = new Models.TaskModel();
            private void Read()
            {
                Tasks = test.GetAllTasks();
            }
        }
    }

    먼저 TaskViewModel로 각 리스트에 들어갈 값을 객체 형태로 만들었고,

    TaskListViewModel에 TaskViewModel를 ObservableCollection에 담아 리스트를 만들었습니다.

     

     

    model부분에는 LIST에 초기값을 설정할 부분을 넣었습니다.

    namespace WPFTODOLIST.Models
    {
        public class TaskModel
        {
            private ObservableCollection<TaskViewModel> tasks;
    
            public ObservableCollection<TaskViewModel> GetAllTasks()
            {
                tasks = new ObservableCollection<TaskViewModel>();
                tasks.Add(new TaskViewModel() { Name = "task 1", Complete = false });
                tasks.Add(new TaskViewModel() { Name = "task 2", Complete = true });
                tasks.Add(new TaskViewModel() { Name = "task 3", Complete = true });
                tasks.Add(new TaskViewModel() { Name = "task 4", Complete = false });
                tasks.Add(new TaskViewModel() { Name = "task 5", Complete = true });
                tasks.Add(new TaskViewModel() { Name = "task 6", Complete = false });
    
                return tasks;
            }
            
            
        }
    }

    이렇게 tasks 컬렉션을 반환해 주어 초기값을 설정해 주었고,

     

    notifier와 delegateCommand는 따로 빼서 관리 해주었습니다.

    namespace WPFTODOLIST.Common
    {
    
        public class DelegateCommand : ICommand
        {
            private readonly Func<bool> canExecute;
            private readonly Action execute;
    
            public DelegateCommand(Action exectue) : this(exectue, null)
            {
            }
    
            public DelegateCommand(Action execute, Func<bool> canExecute)
            {
                this.execute = execute;
                this.canExecute = canExecute;
            }
    
            public event EventHandler CanExecuteChanged;
            public bool CanExecute(object parameter)
            {
                if (this.canExecute == null)
                {
                    return true;
                }
                return this.canExecute();
            }
    
            public void Execute(object parameter)
            {
                this.execute();
            }
    
            public void RaiseCanExecuteChanged()
            {
                if (this.CanExecuteChanged != null)
                {
                    this.CanExecuteChanged(this, EventArgs.Empty);
                }
            }
    
        }
    
    }
    namespace WPFTODOLIST.Common
    {
        public class Notifier : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;
           protected  void OnPropertyChanged(string value)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(value));
            }
        }
    }

    최종적으로 만든 화면입니다. 일정 불러오기를 눌러 보시면 내용이 초기에 설정한 내용이 나오게 되고,

    하단에 제목을 적어 일정 등록을 하게 되면 

    리스트에 값이 싸이는 모습을 보실수 있습니다.

     

    소스는 정리 하여 올려 놓겠습니다.

    봐주셔서 감사합니다. WPF는 한글로 된 포스트가 많이 없는것같아 저도 많이 찾아보고 하고 있습니다.

    많이 포스팅 하겠습니다.

    감사합니다.

    WPFTODOLIST.zip
    0.69MB

     

    반응형

    댓글

Designed by Tistory.