WPF ViewModel 사이의 데이터 전달

안녕하세요, WPF에 입문한 지 얼마 안되는 개발자입니다!

WPF MVVM 패턴을 이용해서 개발 중인데, MainWindow 내에 새로운 Window를 팝업하는 버튼이 있습니다.

새로운 Window를 팝업 시키고, 그 팝업된 윈도우와 데이터 바인딩된 뷰모델의 데이터를 MainWindow의 뷰모델에게 넘기고 싶은데, 어떠한 구조가 좋을지 모르겠습니다.

1 Like

MVVM Toolkit을 사용하신다면  Messenger를 이용하는 방법이 있을 것 같네요.

2 Likes

답변 감사드립니다!

윈도우도 객체라서 다른 프레임워크나 도구가 필요 없습니다.

한 객체에게 데이터를 전달하는 방법은 public set 이 있는 속성을 설정하거나,

// MainWindow.xaml.cs

// Window2 Open 버튼 이벤트 핸들러.
Window2 window2 = new Window2();
window.RequestData = new RequestData
{
   Prop1 = _viewModel.Prop1,
   Prop2 = _vlewModel.Prop2,
   // ...
}

window2.Show();

생성자를 통해 전달하면 되고,

// MainWindow.xaml.cs
private RequestData _request = new(); // 수시로 업데이트 됨.

// Window2 Open 버튼 이벤트 핸들러.

Window2 window2 = new(_request);

window2.Show();

거꾸로 받고 싶다면, public get 속성을 통해 받으면 됩니다.

그러나, 다른 윈도우가 닫히면 속성을 읽을 수 없으므로, 다른 윈도우가 살아 있을 때, 이벤트를 통해 실시간으로 받으면 됩니다.

// Window2.xaml.cs

// ...

public event EventHandler<ResponseData> ResponseDataChanged;


public Window2()
{
   // ...
   _viewModel.PropertyChanged +=  OnViewModelChanged;
}

private void OnViewModelChanged(object s, EventArgs e) =>
   UpdateResponse(_viewModel);

private void UpdateResponse(Window2ViewModel viewModel)
{
    ResponseData response = // _viewModel 로부터 ReponseData 생성.
    ResponseDataChanged?.Invoke(response);
}

public void Dispose()
{
   _viewModel.Propertychanged -= OnViewModelChanged;
}

// MainWindow.xaml.cs

// Window2 Open 버튼 이벤트 핸들러.
Window2 window2 = new(_request);
window2.ResponseDataChanged += OnResponseDataChanged;
window2.Show();
// ...

private void OnResponseDataChanged(ReponseData response)
{
   _viewModel = // response로부터 viewModel 재설정. => 데이터 바인딩에 의해 뷰에 반영됨.
   // ...   
}

만약 Window2가 뷰모델을 공개 속성으로 선언한다면, 그 뷰모델의 PropertyChanged 이벤트를 바로 사용할 수도 있습니다.

// MainWindow.xaml.cs

// Window2 Open 버튼 이벤트 핸들러.
Window2 window2 = new(_request);
window2.ViewModel.PropertyChanged += OnWindow2ViewModelPropertyChanged;
}

private void OnWindow2ViewModelPropertyChanged(object s, EventArgs e) =>
{
   if (s is Window2ViewModel window2ViewModel)
   {
       // window2ViewModel로, MainWindow 뷰모델을 업데이트.
   }
}
3 Likes

메신저보단 IoC(의존성 주입)을 사용하는것을 강력하게 추천드립니다.

2 Likes

답변 감사드립니다!

1 Like

App.cs에 ServiceCollection 등록하는 것 말씀이시죠?
혹시 왜 강력 추천하시는지 말씀해 주실 수 있으신가요?

Messenger를 권장하지 않는 이유는, 의존이 생기기 때문입니다. 특정 메시지 관리하는 서비스에 의존적이게 되죠. (해당 서비스의 요구에 맞춘 추가적인 구현이 필요하고요)

대부분의 경우, A뷰모델에서 B 뷰모델로 데이터를 전달하는게 필요한게 아닌,
사실 앱 전체에서 공유되는 어떤 데이터를 관리할 수 있는 서비스가 필요했을 거라고 추측됩니다.

IoC는 어떤 의존관계에 있는 서비스를 근본적인 방식으로 결합도를 낮추면서도, 관계를 파악하기 쉬운 설계원칙을 적용할 수 있도록 해줍니다(생성자 주입).

IoC컨테이너(Microsoft.Extensions.DependencyInjection)와 같이 활용하면 서비스의 수명주기 관리, 의존 서비스를 알아서(?) 주입해주니까 굉장히 편합니다.

혹시나 예제 필요하시면,
제가 올렸던 게시글 한번 참고하시면 될 거 같습니다.

1 Like

답변 감사드립니다! IoC 활용해서 진행중입니다ㅎㅎ

1 Like