프로그래밍과 잡담

[WPF] MVVM 을 이용하는 유저컨트롤 간의 데이터 처리 본문

프로그래밍/C#

[WPF] MVVM 을 이용하는 유저컨트롤 간의 데이터 처리

크레온 2020. 7. 16. 12:12

인터넷 찾아보면 WPF MVVM  패턴을 구현한 거보면 대부분 이해하기 쉽다.  근데 그 예제들은 이해하기 쉬우라고 쉽게 만들어 놓은거지만 실제 사용 할려면 여러가지가 짬뽕되서 사용해야한다는거지.

 

일단 나도 공부하는 중이라서 여기다 적어 놓는다.

 

유저컨트롤 - 유저컨트롤 간의 데이터 교환을 할려면 결국 인터페이스든 이벤트든 간에 연결이 필요하다.

 

컨트롤A가 있는데 이건 그냥 유저를 추가하는 기능 밖에 없음.

대충 아래와 같이 생김.

 

컨트롤 A

xaml 코드

<UserControl x:Class="MVVM2.ucA.UcA"
             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:local="clr-namespace:MVVM2" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
             mc:Ignorable="d" Height="201" Width="189"
             x:Name="ctrl"
             >
    
    <Grid Background="#FFF6F6F6">
        
        <Label x:Name="label" Content="이름" HorizontalAlignment="Left" Margin="10,41,0,0" VerticalAlignment="Top" Height="27"/>
        <TextBox x:Name="textBox" HorizontalAlignment="Left" Margin="54,41,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" Height="26" Text="{Binding NewUser.Name}"  />
        <Label x:Name="label_Copy" Content="사용자 추가" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Height="27"/> 
        <Label x:Name="label_Copy1" Content="나이" HorizontalAlignment="Left" Margin="10,72,0,0" VerticalAlignment="Top" Height="27"/>
        <TextBox x:Name="textBox_Copy" HorizontalAlignment="Left" Margin="54,72,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" Height="26" Text="{Binding NewUser.Age}" />
        <Label x:Name="label_Copy2" Content="성별" HorizontalAlignment="Left" Margin="10,103,0,0" VerticalAlignment="Top" Height="27"/>
        <TextBox x:Name="textBox_Copy1" HorizontalAlignment="Left" Margin="54,103,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" Height="26" Text="{Binding NewUser.Sex}"/>
        <Button x:Name="btSave" Content="저장"  HorizontalAlignment="Left" Margin="10,150,0,0" VerticalAlignment="Top" Height="24" Width="164" Command="{Binding SaveCommand}" />

    </Grid>
</UserControl>

 

그리고 컨트롤 B는  컨트롤 A에서 추가한 유저 목록을 표시함.  소스는 아래와 같음.

 

xaml

<UserControl x:Class="MVVM2.ucB.UcB"
             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:local="clr-namespace:MVVM2"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">

    <Grid Background="#FFFBFBFB">

        <ListView x:Name="listView" Margin="0,51,0,0" ItemsSource="{Binding UserList}" >
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="이름" Width="100" DisplayMemberBinding="{Binding Name}" />
                    <GridViewColumn Header="나이" Width="100" DisplayMemberBinding="{Binding Age}" />
                    <GridViewColumn Header="성별" Width="100" DisplayMemberBinding="{Binding Sex}" />

                </GridView>
            </ListView.View>
        </ListView>

        <Button x:Name="btLoad" Content="이름" Margin="264,10,10,266" Visibility="Hidden"
                Command="{Binding LoadDataCommand}" />
        <Label x:Name="label" Content="사용자 목록" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" FontSize="16"/>

    </Grid>
</UserControl>

 

하는 일은 간단함.

컨트롤 A에서 유저를 입력하면 B에 추가되서 표시되는거지.

 

그러면 MainWindow에서는 아래와 같이 처리함.

소스는 그냥 제외 처리한다. 그냥 유저컨트롤 두개만 붙이고 배치하면 끝임.

 

이제 중요한거, A에서 B로 데이터를 넘겨줄려면 위에 썼듯이 A하고 B가 연결이 되어야 한다.

근데 A에 B의 인스턴스를 막바로 때려 넣어줘도 상관 없긴하지만, 그렇게 짜 놓으면 실제 현실에서는 기능 추가를 하거나 할 때 졸라 힘들어진다.  둘이 졸라 찰싹 붙어있기 때문에 하나를 수정하면 다른 하나도 영향을 미치기 때문이다.

그래서 인터페이스를 쓰거나 아니면 이벤트를 이용하게 된다. 

 

나는 그냥 인터페이스를 썼음. 사실 이벤트를 써도 되긴하는데 그냥 써봄.

인터페이스하고 구현 부는 아래와 같음.  인터페이스 하나 만들고 메소드 하나 추가한거임 ㅋ

  namespace MVVM2.ucA
  {
      public interface IUcA
      {
          void UserAdded(User user);
      }
  }


//ucA.cs
/// <summary>
/// UcA.xaml에 대한 상호 작용 논리
/// </summary>
public partial class UcA : UserControl
{
  public IUcA interactor { set; private get; }
  private UcAViewModel _vm;

  public UcA()
  {
    InitializeComponent();
    this.DataContext = new UcAViewModel();

    _vm = this.DataContext as UcAViewModel;

    _vm.PropertyChanged += _vm_PropertyChanged;
  }
  
  // 소스 후략
  
}


// UcB.cs

/// <summary>
/// UcB.xaml에 대한 상호 작용 논리
/// </summary>
public partial class UcB : UserControl, IUcA
{
  public IUcB interactor { set; private get; }
  private UcBViewModel _vm;
  public UcB()
  {
    InitializeComponent();

    this.DataContext = new UcBViewModel();
    _vm = this.DataContext as UcBViewModel;

    _vm.PropertyChanged += _vm_PropertyChanged;
  }

  ... 중략


  /// <summary>
  /// 신규 유저가 추가되면 뷰모델 프로퍼티에 값을 입력하면 뷰모델에서 처리함.
  /// </summary>
  /// <param name="user"></param>
  void IUcA.UserAdded(User user) { _vm.NewUser = user; }


}

보다 싶이 그냥 컨트롤A에 인터페이스 속성 하나 만들고 B에서 구현한 걸  Main쪽에서 서로 이어줬다.

 

MVVM에서는 버튼 이벤트를 View에서 직접 처리 하지 않는다.  뷰에서 VM(뷰모델)으로 바인딩을 해줘서 처리하기 때문이다.  A에서 유저 정보를 입력하고 저장을 누르면! 뷰모델에서 저장을 하고 그 결과를 뷰에서 인터페이스를 통해 처리 하라고 해줘야 하는데, 그걸 처리하기 위해서는 나는 아래와 같이 했다. 더 좋은 방법이 있을거 같은데 모르겠어.

 

//UcAViewModel 클래스

// 저장 버튼 클릭 시 처리 하는 커맨드
private ICommand saveCommand;
public ICommand SaveCommand
{
  get
  {
  	return saveCommand ?? (this.saveCommand = new DelegateCommand(SaveUser));
  }
}

private void SaveUser()
{
  User user = new User();
  user.Name = NewUser.Name;
  user.Age = NewUser.Age;
  user.Sex = NewUser.Sex;

  UserList.Add(user);
  // 아래와 같이 유저가 추가되면 이벤트를 호출 해준다.
  OnPropertyChanged("UserAdded");
}


//UcA 클래스
public UcA()
{
  InitializeComponent();
  this.DataContext = new UcAViewModel();

  _vm = this.DataContext as UcAViewModel;

  _vm.PropertyChanged += _vm_PropertyChanged;
}

// 이 부분은 위에서 UserAdded가 이벤트가 발생되면 여기서 받을 수 있다.
private void _vm_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
  // 유저가 추가되면
  if( e.PropertyName == "UserAdded")
  {
    // 연결된 인터페이스에 알려줌
    interactor.UserAdded(_vm.NewUser);
  }
}

 

그냥 이렇게 처리 했음.

뭔가 더 좋은게 있을련지 모르겠는데.. 일단 못찾겠으니 이렇게 해 놔야겠다.

 

실행 결과는 아래와 같다. 저장을 누르면 바로 사용자 목록에 추가되고 리스트에서 바로 표시된다.

 

 

전체 소스를 보고 싶으면 보고  나중에 내가 까먹으면 볼려고 써 놓음.

 

MVVM2.zip
0.23MB

반응형

'프로그래밍 > C#' 카테고리의 다른 글

Parallel for 문 사용 관련  (0) 2023.02.14
[C#] SerialPort 사용 시 주의 점  (0) 2022.07.30
c#에서 java final 과 비슷한 기능 쓰기  (0) 2019.12.31
Comments