# [MVVM] ViewModel에서 View 참조

응용 애플리케이션을 만들 때 [MVVM](https://ko.wikipedia.org/wiki/%EB%AA%A8%EB%8D%B8-%EB%B7%B0-%EB%B7%B0%EB%AA%A8%EB%8D%B8) 패턴을 적용하면 뷰와 뷰에 데이터를 전달하는 뷰모델 간 책임을 분리할 수 있습니다.

대부분의 경우 데이터 바인딩을 통해 뷰모델의 데이터를 뷰에 표시하고 갱신할 수 있습니다.

그런데 MVVM에서 [명령어](https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/may/mvvm-commands-relaycommands-and-eventtocommand)를 뷰모델에서 처리할 때 뷰의 동작이 필요할 때가 있습니다.

예를 들어보겠습니다.

화면상에서 텝에 새로운 컨텍스트가 추가될 때 컨텍스트의 이름을 설정해야 하고 이 이름을 팝업 윈도우를 통해 입력 받아야 한다고 가정해 봅시다.

1. [뷰] 텝 추가 버튼 클릭
1. [뷰모델] 컨텍스트 추가
  1. [뷰] 컨텍스트 이름 팝업 입력
  1. [뷰모델] 입력받은 이름으로 컨텍스트 추가
1. [뷰] 컨텍스트 바인딩에 의해 탭 표시, 내용 표시...

다른 과정은 데이터 바인딩을 통해 가능한데 '2-1'의 경우 뷰모델에서 뷰의 메서드를 호출해야만 합니다. 하지만 뷰모델에서 뷰를 참조하게 되면 MVVM 패턴에 위반됩니다. 이를 [SOLID](https://ko.wikipedia.org/wiki/SOLID_(%EA%B0%9D%EC%B2%B4_%EC%A7%80%ED%96%A5_%EC%84%A4%EA%B3%84)) [원칙 의존관게 역전 원칙](https://ko.wikipedia.org/wiki/%EC%9D%98%EC%A1%B4%EA%B4%80%EA%B3%84_%EC%97%AD%EC%A0%84_%EC%9B%90%EC%B9%99)을 사용하면 해결됩니다. 이는 [IoC](https://ko.wikipedia.org/wiki/%EC%A0%9C%EC%96%B4_%EB%B0%98%EC%A0%84)에서도 동일한 원리로  사용됩니다.

이를 위해 뷰모델은 뷰를 그대로 참조하지 않고 인터페이스로 참조해서 뷰는 그 인터페이스를 구현하고 뷰모델은 인터페이스로 참조하는 것으로 직접적인 뷰모델과 뷰간 참조 관계가 없도록 합니다.


## 인터페이스로 관계 명세

간단한 두개의 인터페이스로 시작합니다. 

```csharp
public interface IViewAction
{
}

public interface IHaveViewAction<TViewAction>
    where TViewAction : IViewAction
{
    TViewAction? ViewAction { get; set; }
}
```

`IViewAction`은 뷰 액션을 의미하며 `IHaveViewAction`의 제네릭 인자가 뷰 액션임을 나타냅니다.
`IHaveViewAction<TViewAction>`은 뷰가 뷰 액션을 소유함을 의미하며 다음처럼 사용할 수 있습니다.

| 뷰모델
```csharp
public partial class RepositoryViewModel : ObservableRecipient, IViewModel, IHaveViewAction<IRepositoryViewAction>
{
    public IRepositoryViewAction? ViewAction { get; set; }
...
```

> IViewModel도 해당 클래스가 뷰모델임을 나타내는 빈 인터페이스입니다.

뷰는 다음의 모습이 됩니다.

| 뷰
```csharp
public sealed partial class RepositoryPage : ViewModelPage, IView<RepositoryViewModel>, IRepositoryViewAction
{
    public RepositoryPage()
    {
        InitializeComponent();

        ViewModel.ViewAction = this;
    }
...
```

이제 `RepositoryPage`는 `IRepositoryViewAction` 인터페이스를 구현하는 것으로 뷰모델에서 MVVM 패턴을 해치지 않으면서 뷰의 기능을 사용할 수 있게 됩니다.

