User Control 과 Vimewodel

안녕하세요.
공부하고 있는 학생입니다.

WPF는 일반적으로 MVVM 기반으로 구현하고 있다는것을 알았습니다.

현재까지 제가 이해한 View와 Viewmodel은 이렇습니다.

View → 화면에 나타낼 요소들을 구성하는 페이지
ViewModel → 화면에 나타낼 요소들의 비즈니스 로직을 구현하는 페이지

여기서 페이지라 함은 그냥… 어떻게 표현해야 할지 몰라서 얘기한 것입니다.
윈도우 창으로 구성된 뷰와 뷰모델을 연결시키고 바인딩 하는것은 어느정도 이해가 되었고, UserControl을 찾다보니 gpt가 usercontrol도 Viewmodel을 가지는것이 일반적이 다라고 제시하여 찾다보니 UserControl은 뷰모델을 가지지 않아야 한다. 라는 의견이 있더라구요.

감히 GPT의 말을 거스르려는것은 아니지만 결국 userControl도 Control이라는 이름을 가진것 보니… 일반적인 버튼들도 뷰모델이 없으니까 Viewmodel을 통한 로직처리가 어불성설이다 라는 생각이 들더라구요.

여기서 제가 궁금한것은 아래 그림과 같은 페이지를 구성하고 처리하려고 한다면 어떤 방법이 일반적으로 더 많이 쓰이는지,
뷰모델을 통한 비즈니스 로직 처리가 아니라면 어떤식으로 비즈니스 로직을 처리하는지 궁금합니다.

우측 버튼들을 순차적으로 1번 2번 3번이라 하고 1번 버튼을 클릭하면 1번 usercontrol을 좌측탭에 로드하고 2번 버튼을 클릭하면 2번 usercontrol을
좌측탭에 로드하고 싶다면 어떻게 하면되나요??

너무 기본적인 질문이라 죄송합니다

2개의 좋아요

MVVM 은 WPF와 함께 소개되기는 했지만, WPF에 한정된 것은 아닙니다.
윈폼에도 적용할 수 있으며, 하다 못해 콘솔앱에도 적용할 수 있습니다.

질문의 그림으로 설명을 드리면,

첫째로 그러한 모양으로 보이도록 하는 것은 View의 역할입니다.
우측의 네모난 상자가 버튼이라면, 버튼 모양으로 보이게 하는 것도, 버튼 처럼 행동하는 것 - 클릭하면 눌려지는 액션을 하는 것도 뷰의 역할입니다.

둘째로, 버튼이 우측에서 좌측으로 넘어가는 것처럼 보이게 만드는 것도 View 의 일입니다.

그런데, 그 넘김의 의미가, 로직적 의미 - 예를 들면, 추가나 삭제할 항목을 표현하는 것이라면, 그 항목의 관리는 ViewModel 의 업무입니다.

public class ViewModel
{
   // 로직을 위한 상태
   public List<Item> Stored {get; set;} = [];
   public List<Item> Temp { get set; } = [];

   // 로직
   public void MoveToTemp(string itemName)
   {
      if (Stored.FirstOrDefault(x => x.Name == itemName) is Item item)
         Temp.Add(item);
   } 
}
// Psuedo View
<LeftSection> 
   <ItemsGrid/> // _viewModel.Temp 에 바인딩
</LeftSectoin>
<RightSection>
   <ItemsStack/> // _viewModel.Stored 에 바인딩
</RightSection>
// View Code-behind
private ViewModel _viewModel;

private void OnButtonOnItemStackClicked(object? s, EventArgs e)
{
   if (s is Button button) 
   {
      _viewModel.MoveToTemp(button.Text);
   }   
}

보시다시피, 뷰는 뷰모델의 상태를 화면에 반영하기만 할 뿐 스스로 상태를 저장하지 않습니다.
또한 뷰는 로직을 구현하지 않고, 뷰모델에 있는 로직을 (코드 비하인드에서) 호출할 뿐입니다.

뷰와 뷰모델 사이에 통신은 코드 비하인드(Command)와 데이터 바인딩(Query)을 통해 이뤄짐을 알 수 있습니다.

뷰모델이 이렇게 설계되어 있다면, 이 뷰모델은 윈폼, 콘솔 뿐만 아니라, 어떤 UI 프레임워크에도, 그대로 사용할 수 있습니다.

이렇게 설계하면 뷰와 로직이 분리됐다고 보는 것이며, MVVM이 추구하는 바입니다.

MVVM이 잘 지켜지고 있는 지, 보다 엄밀히 말하면, 로직과 뷰가 적절하게 분리되었는 지 궁금하다면 뷰는 손을 안대고, 로직만 변화시켜도 전체 소프트웨어에 아무런 문제가 없는지를 확인하면 됩니다.

public class ViewModel
{
   // ...

   // 로직 구현의 수정
   public void MoveToTemp(string itemName)
   {
      if (Stored.FirstOrDefault(x => x.Name == itemName) is Item item
         && Temp.FirstOrDefault(x => x.Name == itemName) is null)
         Temp.Add(item);
   } 
}

WPF는 MVVM을 지원하는 여러 가지 객체를 제공하기 때문에 그 패턴을 따르면 소프트웨어를 작성하고 유지 보수할 때 편리한 것은 맞습니다.

그러나, 반드시 엄밀하게 따라야 하는 것이 진리일 수는 없습니다.
왜냐하면, 대부분의 디자인 패턴은 미래의 유지보수라는 수익을 위해 오늘의 손가락 품을 열심히 팔 것을 요구기 때문입니다.

그 만큼 보일러 플레이트 코드가 많다는 의미입니다.

지금 당장, 자원이 부족하다면 코드 비하인드에 다 때려 넣는 선택을 하더라도, 소프트웨어를 동작시키는 것에는 아무런 문제가 없습니다.

실제로 해보시면, 어떤 게 분리되어야 할 로직인 지를 결정하는 게 훨씬 더 어렵다고 느낄 것입니다.

2개의 좋아요

사용자 정의(user defined control) 컨트롤과 UserControl을 구분해서 생각하셔야합니다.

  1. 일반적으로 View는 Window 또는 UserControl 클래스를 상속받아 구현합니다.

  2. View는 다수개의 컨트롤의 조합으로 구성되며 컨트롤은 WPF에서 제공하는 기본 컨트롤을 사용하거나 사용자가 UserControl 클래스 또는 상위 컨트롤 클래스를 상속 받아 user defined control을 구현할 수 있습니다.

UserControl은 View를 구현하거나 사용자 정의 컨트롤을 구현하는데 모두 쓰일 수 있습니다.

여기서 말하는 UserControl은 1의 View를 구현하기 위한 UserControl이 아닌 2의 user defined control을 의미합니다.

따라서 문의 주신 페이지 구성은 알고 계신 방법대로 UserControl을 상속 받아 View에 해당하는 1, 2의 페이지를 구성하시고 View Model을 참조하여 사용하시면 됩니다.

2개의 좋아요

두분 다 답변 채택이 불가능하여 그냥… 두겠습니다…!
두분 다 진심으로 감사드립니다

2개의 좋아요

제가 이해한 바가 맞는지 확인 차 댓글 남겨봅니다…

View → Window/UserControl 로 구현함.
이 Window와 UserControl은 다수의 컨트롤로 조합됨.
이 때 다수의 컨트롤은 WPF에서 기본적으로 제공하는 기본 Cotrol과 사용자가 직접 정의해서 사용하는 userDefined Control을 의미함.

User Defined Control 은 WPF에서 제공하는 Control과 같기 때문에 ViewModel을 가질 필요 없음.
User Control은 일반적인 View에 해당하기 때문에 ViewModel에서 비즈니스 로직을 처리하면 됨.

3개의 좋아요

넵. 이해하신 내용이 맞습니다:blush:

1개의 좋아요