티스토리 뷰

반응형

2022.09.06 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내v1.0 part9-2 StyleSelector

2022.08.31 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 v1.0 part9-1 DataTemplateSelector

2022.08.08 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 v1.0 part8-3 Template

2022.08.02 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 v1.0 part8-2 Template

2022.07.21 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 v1.0 part8-1 Template

2022.07.13 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 v1.0 part7 Behavior

2022.07.05 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 V1.0 part6 Command

2022.06.27 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 V1.0 part5 Converter

2022.06.15 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 V1.0 part4-2 Data Binding

2022.06.13 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 V1.0 part4-1 Data Binding

2022.06.07 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 V1.0 part3-3

2022.06.02 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 V1.0 part3-2

2022.05.30 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 V1.0 part3-1

2022.05.11 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 v1.0 part2

2022.05.09 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 v1.0 part1

1. 준비

part3-2를 시작하기 전에 Microsoft.Xaml.Behaviors.Wpf Nuget package 설치가 반드시 필요합니다.

자세한 사항은 여기를 참고하시기 바랍니다.

 

2. 아이템 선택시 해당 내용 표시하기

Event -> MainWindow.xaml

DataGrid에 SelectionChanged 이벤트 핸들러를 이용해서 선택된 사용자가 변경이되면, 상세 정보를 출력합니다.

        <DataGrid
            x:Name="MemberDataGrid"
            Grid.Row="1"
            Margin="0,10,0,0"
            AutoGenerateColumns="False"
            IsReadOnly="True"
            SelectionChanged="MemberGrid_SelectionChanged">
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding Name, Mode=TwoWay}" Header="Name" />
                <DataGridTextColumn Binding="{Binding Phone, Mode=TwoWay}" Header="Phone" />
                <DataGridTextColumn Binding="{Binding RegDate, StringFormat={}{0:d}}" Header="Regested Date" />
                <DataGridCheckBoxColumn Binding="{Binding IsUse, Mode=TwoWay}" Header="Use" />
            </DataGrid.Columns>
        </DataGrid>

Event -> MainWindow.xaml.cs

  • MemberDataGrid의 SelectedItem 프로퍼티를 Member로 형변환 후에 DisplayMember 메소드를 이용해서 데이터를 각 컨트롤의 Text 프로퍼티에 출력합니다.
  • 이 방법은 Member의 Id 프로퍼티 값과 Id.Text 데이터는 각각 따로 존재합니다.
  • MemberDataGrid.SelectedItem이 null인지를 확인해서 Edit, Delete 버튼들의 사용가능 여부를 직접 변경합니다.
        private void MemberGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            DisplayMember(MemberDataGrid.SelectedItem as Member);
            ChangeButtonIsEnable();
        }
        
        private void DisplayMember(Member source)
        {
            if(source == null)
            {
                ClearDetail();
                return;
            }
            Id.Text = source.Id.ToString();
            Name.Text = source.Name.ToString();
            Phone.Text = source.Phone.ToString();
            RegDate.Text = source.RegDate.ToString();
            IsUse.IsChecked = source.IsUse;
            IsUse.Content = source.IsUse ? "사용" : "미사용";
        }        
        
        private void ChangeButtonIsEnable()
        {
            if(MemberDataGrid.SelectedItem == null)
            {
                EditButton.IsEnabled = false;
                DeleteButton.IsEnabled = false;
            }
            else
            {
                EditButton.IsEnabled = true;
                DeleteButton.IsEnabled = true;
            }
        }

Mvvm ->  MainWindow.xaml

  • 먼저 b라는 namespace를 추가합니다.
  • DataGrid 내부에 EventTrigger와 InvokeCommandAction을 이용해서 SelectionChanged 이벤트가 발생했을 때 SelectionChangedCommand를 실행할 수 있도록 만들어 줍니다.
    • Button 컨트롤을 제외한 모든 컨트롤은 이 방법을 이용해서 이벤트와 커맨드를 연결합니다.
  • InvokeCommandAction의 PassEventArgsToCommand="True"는 이벤트가 발생할 때 전달되는 EventArgs를 CommandParameter로 전달할지 여부를 지정할 수 있습니다.
  • 코드를 번역하면, "DataGrid에 SelectionChanged 이벤트가 발생하면, ViewModel의 SelectionChangedCommand를 실행하는데, EventArgs를 CommandParameter로 전달해라" 입니다.
  • 데이터를 출력하는 컨트롤들은 EditMember 프로퍼티의 하위 프로퍼티들을 바인딩 하도록 구성합니다.
  • TextBox의 UpdateSourceTrigger=PropertyChanged는 사용자가 값을 변경하는 즉시, 바인딩된 프로퍼티의 값도 변경하도록 지정합니다. 기본값은 LostFocus입니다.
    xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
    ...
        <DataGrid
            x:Name="MemberDataGrid"
            Grid.Row="1"
            Margin="0,10,0,0"
            AutoGenerateColumns="False"
            IsReadOnly="True"
            ItemsSource="{Binding Members}">
            <b:Interaction.Triggers>
                <b:EventTrigger EventName="SelectionChanged">
                    <b:InvokeCommandAction Command="{Binding SelectionChangedCommand}" 
                                           PassEventArgsToCommand="True" />
                </b:EventTrigger>
            </b:Interaction.Triggers>
            <DataGrid.Columns>
            ...
            </DataGrid.Columns>
        </DataGrid>

            <TextBlock
                x:Name="Id"
                Grid.Column="1"
                Margin="4"
                Text="{Binding EditMember.Id}" />
            <TextBox
                x:Name="Name"
                Grid.Row="1"
                Grid.Column="1"
                Margin="4"
                Text="{Binding EditMember.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
            <TextBox
                x:Name="Phone"
                Grid.Row="2"
                Grid.Column="1"
                Margin="4"
                Text="{Binding EditMember.Phone, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
            <TextBlock
                x:Name="RegDate"
                Grid.Row="3"
                Grid.Column="1"
                Margin="4"
                Text="{Binding EditMember.RegDate}" />
            <CheckBox
                x:Name="IsUse"
                Grid.Row="4"
                Grid.Column="1"
                Margin="4"
                IsChecked="{Binding EditMember.IsUse, Mode=TwoWay}" />

Mvvm -> MainViewModel.cs

  • SelectionChangedCommand를 추가합니다.
  • EditMember 프로퍼티를 추가합니다.
  • SelectionChangedCommand를 RelayCommand를 이용해서 생성합니다. 이 때 CommandParameter 값을 받아서 사용해야 하기 때문에 new RelayCommand<object>()를 이용합니다.
  • EditMember에 방금 선택된 Member의 Clone() 객체를 입력합니다.
    • 선택된 Member 객체를 그대로 넣으면, 수정이 되어 취소를 할 수 없기 때문에 Clone된 객체를 넣어 둡니다.
        public IRelayCommand SelectionChangedCommand { get; set; }

        private Member _editMember;
        public Member EditMember
        {
            get { return _editMember; }
            set { SetProperty(ref _editMember, value); }
        }
        
        private void Init()
        {
            ...
            SelectionChangedCommand = new RelayCommand<object>(OnSelectionChanged);
        }
        
        private void OnSelectionChanged(object para)
        {
            var args = para as SelectionChangedEventArgs;
            if(args == null)
            {
                return;
            }
            
            if(args.AddedItems.Count == 0)
            {
                EditMember = null;
                return;
            }
            else
            {
                var member = args.AddedItems[0] as Member;
                EditMember = (Member)member.Clone();
            }

        }
SelectionChanged 이벤트를 이용해서 화면에 출력하도록 구성했지만, DataGrid의 SelectedItem을 직접 ViewModel에서 바인딩해서 사용하는 경우가 더 많습니다.
다양한 방법이 가능하기 때문에 선택적으로 사용하실 수 있습니다. 
딱 한가지 방법으로만 출력하는 이벤트 방식과의 차이점이면서, 개발자에게 선택 장애를 발생시키는 이유이기도 합니다.

실행 화면

3. Edit, Delete 버튼 사용 가능 여부 변경

EditMember가 null이면 사용 불가, null이 아니면 사용 가능인데, 버튼 컨트롤의 IsEnable 속성을 직접 제어하는 것이 아니라 Command의 사용 가능 여부를 변경하는 것으로 처리를 합니다.

Mvvm -> MainViewModel.cs

  • EditCommand를 생성할 때 뒤에 () => EditMember != null 이라는 실행 가능 조건을 추가합니다.
  • PropertyChanged += MainViewModel_PropertyChanged를 추가해서, 뷰모델에서 발생하는 프로퍼티 체인지 이벤트 핸들러를 추가합니다.
  • 뷰모델에서 변경된 프로퍼티의 이름이 EditMember라면 EditCommand.NotifyCanExecuteChanged() 메소드를 호출해서 커맨드의 실행 가능 여부를 확인합니다.
실행 가능 여부를 확인하는 메서드의 이름은 라이브러리의 종류에 따라 다릅니다. 하지만, 대부분 Can이라는 글씨를 포함하고 있으니 쉽게 알 수 있습니다.
Command가 연결된 Button은 IsEnable 프로퍼티를 직접 수정하는 것 보다 Command의 사용 가능 여부가 우선 순위를 가지고 있습니다.
        private void Init()
        {
            ...
            
            EditCommand = new RelayCommand(() => IsEditing = true, () => EditMember != null);
            DeleteCommand = new RelayCommand(OnDelete, () => EditMember != null);

            PropertyChanged += MainViewModel_PropertyChanged;
        }

        private void MainViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            switch(e.PropertyName)
            {
                case nameof(EditMember):
                    EditCommand.NotifyCanExecuteChanged();
                    DeleteCommand.NotifyCanExecuteChanged();
                    break;
            }
        }

        private void OnDelete()
        {
        }

Mvvm -> MainWindow.xaml

EditButton, DeleteButton에 커맨드를 연결합니다.

            <Button
                x:Name="EditButton"
                Width="80"
                Margin="5,0,0,0"
                Command="{Binding EditCommand}"
                Content="Edit"
                Visibility="{Binding IsEditing, Converter={StaticResource ReversBoolToVisibilityConverter}}" />
            <Button
                x:Name="DeleteButton"
                Width="80"
                Margin="5,0,0,0"
                Command="{Binding DeleteCommand}"
                Content="Delete"
                Visibility="{Binding IsEditing, Converter={StaticResource ReversBoolToVisibilityConverter}}" />

실행 화면

실행 후 선택된 Member가 없을 때는 Edit, Delete Button이 비활성화 되어 있습니다.

Member를 선택하면 Edit, Delete 버튼이 활성화 됩니다.

4. 소스

CrudSample.Core, CrudSample.Event, CrudSample.Mvvm

 

GitHub - kaki104/WpfTest

Contribute to kaki104/WpfTest development by creating an account on GitHub.

github.com

 

반응형
댓글