MVVM이란?

완료됨

MVVM을 사용하지 않는 .NET MAUI 앱은 일반적으로 코드 숨김 파일에 코드가 더 많이 포함되어 있습니다. .NET MAUI의 코드 숨김 파일은 {something}.xaml.cs 패턴을 따릅니다. 코드 숨김 파일에 있는 대부분의 코드는 일반적으로 UI(사용자 인터페이스) 동작을 제어합니다. UI 동작에는 색상이나 텍스트 변경과 같이 UI에 발생하는 모든 작업이 포함될 수 있습니다. 그리고 UI ‘때문에’ 발생하는 모든 것(예: 단추 클릭 처리기)을 포함할 수 있습니다.

이러한 방식의 한 가지 문제는 코드 숨김 파일에 대한 단위 테스트를 작성하기 어렵다는 것입니다. 코드 숨김 파일은 XAML 구문 분석을 통해 생성되거나 다른 페이지에서 생성된 애플리케이션 상태를 가정하는 경우도 많습니다. 이러한 조건은 단위 테스트 실행기에서 처리하기 어려우며, 심지어 사용자 인터페이스는 커녕 모바일 디바이스에서 실행되지 않을 수도 있습니다. 따라서 단위 테스트를 통해 해당 파일에 포함된 UI 동작을 테스트할 수 있는 경우는 드뭅니다.

그러나 MVVM 패턴이 유용한 경우는 다음과 같습니다. MVVM 패턴을 올바르게 사용하면 대부분의 UI 동작 논리가 viewmodel이라는 단위 테스트 가능 클래스로 옮겨져서 이러한 문제가 해결됩니다. MVVM 패턴은 데이터 바인딩을 지원하는 프레임워크에 가장 일반적으로 사용됩니다. .NET MAUI를 사용하면 각 UI 요소를 viewmodel에 데이터 바인딩하여 뷰 또는 코드 숨김에 포함된 코드를 없애거나 거의 없앨 수 있기 때문입니다.

MVVM 애플리케이션에는 어떤 부분이 있나요?

viewmodel은 MVVM 패턴의 고유한 부분이지만, 이 패턴은 모델 부분과 부분도 정의합니다. 이러한 부분에 대한 정의는 MVC(Model-View-Controller)와 같은 다른 일반적인 패턴과 일치합니다.

모델이란?

MVVM 애플리케이션에서 모델이라는 용어는 비즈니스 데이터 및 작업을 나타내는 데 사용됩니다. 모델은 앱의 사용자 프레젠테이션과 관련이 없습니다.

모델에 속하는 코드를 결정하는 데 유용한 규칙은 여러 플랫폼에서 이식 가능해야 한다는 것입니다. 모바일 앱에서 웹 인터페이스 또는 명령줄 프로그램까지, 모든 인스턴스에서 동일한 모델을 사용합니다. 이는 사용자에게 정보가 표시되는 방식과는 관련이 없습니다.

시나리오의 HR 애플리케이션을 생각해 보면, 모델에는 엔터티에 대한 데이터와 논리를 보유하는 Employee 클래스와 Department 클래스가 포함될 수 있습니다. 모델에는 지속성 논리를 유지하는 EmployeeRepository 클래스 등도 포함될 수 있습니다. 일부 다른 소프트웨어 디자인 패턴은 리포지토리 같은 요소를 모델과 별개로 간주합니다. 하지만 MVVM의 경우에는 모든 비즈니스 논리 또는 비즈니스 데이터를 모델의 일부로 간주합니다.

다음은 C# 형식 모델의 두 가지 예제입니다.

public class Employee
{
    public int Id { get; }
    public string Name { get; set; }
    public Employee Supervisor { get; set; }
    public DateTime HireDate { get; set; }
    public void ClockIn() { ... }
}

public class EmployeeRepository
{
    public IList<Employee> QueryEmployees() { ... }
    ...
}

뷰란?

코드는 단추 및 입력 필드와 같은 컨트롤뿐만 아니라 테마, 스타일, 글꼴과 같은 기타 순수한 시각적 요소와 같이 사용자와 직접 상호 작용하는 항목을 제어합니다.

.NET MAUI에서는 뷰를 직접 생성하기 위해 C# 코드를 작성할 필요가 없습니다. 대신 XAML 파일로 뷰를 정의하는 경우가 많습니다. 물론 코드를 통해 사용자 고유의 뷰를 만드는 맞춤형 사용자 정의 컨트롤을 요구하는 상황이 있습니다.

viewmodel이란?

그러면 viewmodel을 살펴보겠습니다. viewmodel은 비즈니스 논리(모델)와 뷰(UI) 사이의 중개자입니다.

viewmodel이 모델과 뷰 간의 중개자 역할을 하는 방법을 보여 주는 다이어그램

viewmodel이 HR 애플리케이션에 대해 수행할 수 있는 작업을 생각해 보세요. 직원의 사용 가능한 휴가 시간을 표시하는 뷰가 있으며 잔여 휴가를 “2주, 3일, 4시간”으로 표시한다고 가정해 보겠습니다. 그러나 모델의 비즈니스 논리는 8시간 근무일의 총 일수를 나타내는 10진수인 13.5일과 동일한 값을 제공합니다. 개체 모델은 다음 목록과 같을 수 있습니다.

  • 모델 - 메서드를 포함하는 Employee 클래스:

    public decimal GetVacationBalanceInDays()
    {
        //Some math that calculates current vacation balance
        ...
    }
    
  • ViewModel - 다음과 같은 속성이 포함된 EmployeeViewModel 클래스:

    public class EmployeeViewModel
    {
        private Employee _model;
    
        public string FormattedVacationBalance
        {
            get
            {
                decimal vacationBalance = _model.GetVacationBalanceInDays();
                ... // Some logic to format and return the string as "X days, Y days, Z hours"
            }
        }
    }
    
  • - 레이블 하나와 닫기 단추가 포함된 XAML 페이지. 레이블에는 viewmodel의 속성에 대한 바인딩이 있습니다.

    <Label Text="{Binding FormattedVacationBalance}" />
    

    다음으로, EmployeeViewModel의 인스턴스로 설정된 페이지에 대한 BindingContext가 필요합니다.

이 예제에서 모델에는 비즈니스 논리가 포함됩니다. 이 논리는 시각적 표시 또는 디바이스에 바인딩되지 않습니다. 핸드헬드 디바이스 또는 데스크톱 컴퓨터에 동일한 논리를 사용할 수 있습니다. 뷰는 비즈니스 논리를 전혀 인식하지 못합니다. 레이블과 같은 뷰 컨트롤은 화면에서 텍스트를 가져오는 방법을 알고 있지만 잔여 휴가인지 임의의 문자열인지는 신경 쓰지 않습니다. viewmodel은 두 세계를 약간 알기 때문에 중개자 역할을 수행할 수 있습니다.

viewmodel이 중개자 역할을 수행하는 방식은 흥미롭습니다. 뷰가 바인딩할 수 있는 속성을 공개합니다. 공용 속성은 viewmodel이 데이터를 제공하는 유일한 방법입니다. 이를 통해 “viewmodel”이라고 불리는 이유를 알 수 있습니다. MVVM의 “모델”은 비즈니스 프로세스의 구조, 데이터 및 논리를 나타내는 반면 “viewmodel”은 뷰가 쿼리하는 구조, 데이터 및 논리를 나타냅니다.

뷰는 viewmodel에서 어떻게 작동하나요?

viewmodel과 모델의 관계를 살펴보면 이는 표준 클래스 간 관계입니다. viewmodel에는 모델의 인스턴스가 있으며 속성을 통해 모델의 측면을 뷰에 노출합니다. 그런데 뷰는 viewmodel에서 속성을 어떻게 가져와서 설정하나요? viewmodel이 변경되면 뷰는 어떻게 시각적 컨트롤을 새 값으로 업데이트하나요? 대답은 데이터 바인딩입니다.

viewmodel의 속성은 개체가 뷰에 바인딩된 시점에 읽습니다. 그러나 바인딩은 바인딩이 뷰에 적용된 후 viewmodel의 속성이 변경되는지 알 수 없습니다. viewmodel을 변경해도 바인딩을 통해 새 값이 뷰에 자동으로 전파되지는 않습니다. viewmodel에서 뷰로 업데이트하려면 viewmodel이 System.ComponentModel.INotifyPropertyChanged 인터페이스를 구현해야 합니다.

INotifyPropertyChanged 인터페이스는 PropertyChanged라는 단일 이벤트를 선언합니다. 이는 값을 변경한 속성의 이름인 단일 매개 변수를 사용합니다. .NET MAUI에 사용되는 바인딩 시스템은 이 인터페이스를 이해하고 해당 이벤트를 수신 대기합니다. viewmodel에서 속성이 변경되고 이벤트가 발생하면 바인딩이 변경 대상에 알립니다.

직원 viewmodel을 사용하여 HR 애플리케이션에서 어떻게 작동하는지 생각해 보세요. viewmodel에는 직원의 이름과 같은 직원을 나타내는 속성이 있습니다. viewmodel은 INotifyPropertyChanged 인터페이스를 구현하고 Name 속성이 변경되면 다음과 같이 PropertyChanged 이벤트가 발생합니다.

using System.ComponentModel;

public class EmployeeViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler? PropertyChanged;
    private Employee _model;

    public string Name
    {
        get {...}
        set
        {
            _model.Name = value;
            OnPropertyChanged(nameof(Name))
        }
    }

    protected void OnPropertyChanged(string propertyName) =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

직원의 세부 정보를 설명하는 뷰에는 viewmodel의 Name 속성에 바인딩된 레이블 컨트롤이 포함됩니다.

<Label Text="{Binding Name}" />

viewmodel에서 Name 속성이 변경되면 해당 속성의 이름으로 PropertyChanged 이벤트가 발생합니다. 바인딩은 이벤트를 수신 대기한 다음, 레이블에 Name 속성이 변경되었다는 것을 알립니다. 그런 다음, 레이블의 Text 속성이 최신 값으로 업데이트됩니다.

지식 점검

1.

개발자가 .NET MAUI 애플리케이션에서 작업 중이며 MVVM 패턴을 구현하려고 합니다. 비즈니스 데이터 및 작업에 대한 모델과 사용자 상호 작용에 대한 뷰를 만들었습니다. 모델과 뷰 간의 중개자 역할을 하기 위해 다음에 무엇을 만들어야 하나요?

2.

팀은 .NET MAUI를 사용하여 모바일 애플리케이션을 개발하고 있으며 비즈니스 논리가 여러 플랫폼에서 이식 가능한지 확인하려고 합니다. 이 비즈니스 논리를 MVVM 패턴에서 어디에 배치해야 하나요?