IT’s Ha

[Xamarin] Xamarin.Forms MVVM 디자인 패턴 적용 본문

.NET/Xamarin

[Xamarin] Xamarin.Forms MVVM 디자인 패턴 적용

Deleloper Ha 2023. 1. 16. 23:22
728x90
반응형

Xamarin.Forms에서 MVVM 패턴의 사용을 설명하려고합니다.

먼저, MVVM패턴에 대하여 설명하고자 합니다.

M(Model) - V(View) - VM(ViewModel)를 합친 용어입니다.  아래의 그림은 Microsoft에서 나와 있는 좋은 설명 그림을 참조 하였습니다.

View - View Model -  Model

그림을 설명하면 View는 ViewModel를 알고있고, ViewModel은 Model를 알고있다. 하지만, Model은 ViewModel를 모르고, ViewModel은 View를 알지 못한다. 따라서 한방향으로만 의존성을 가지고 있다고 할 수 있습니다.

1. View 

View는 실제 화면이 보여지는 화면입니다. Xamarin에서는 Xaml가 해당됩니다. View에서는 Logic을 구현하지 않습니다. Logic은 View Model에서 구현합니다.

2. View Model

View Model은 View와 상호 작용하기 위해, Data를 Binding합니다. 실제 Logic작성은 여기서 합니다. 상황에 따라 Command나 Behavior를 사용 할 수 있습니다.

3. Model

모델은 일반적으로 비즈니스 및 유효성 검사 논리와 함께 데이터 모델을 포함하는 앱의 도메인 모델을 나타내는 것으로 생각할 수 있습니다.

반응형

 

이제부터 예제를 시작하겠습니다.

 먼저 빈 프로젝트를 만듭니다.

폴더 생성

Model, View, ViewModel 디렉토리를 생성합니다.  각각의 폴더에 구분을 지어 구현하려고 합니다.

디렉토리 구조

1. ViewModel 아래에 Public이라는 폴더와 Login이라는 폴더를 추가 하였고, 각각 BaseViewModel과 LoginViewModel을 생성하였습니다.

BaseViewModel.cs

using System;
using System.ComponentModel;

namespace test.ViewModel
{
	public class BaseViewModel : INotifyPropertyChanged
	{

        protected virtual void OnPropertyChanged(string propName)
        {
            if (this.PropertyChanged != null)
                this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
        public event PropertyChangedEventHandler PropertyChanged;

    }
}

데이터의 변경을 View로 알려주기 위해 기본 구성을 작성하였습니다. 위의 BaseViewModel을 가지고 상속을 받아 다른 ViewModel을 작성하기 위하여 구분을 지었습니다. 만약 BaseViewModel을 가져가지 않는다면, 프로그램 라인이 더 길어집니다. 

LoginViewModel.cs

using System;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Forms;

namespace test.ViewModel
{
	public class LoginViewModel : BaseViewModel
	{
		public LoginViewModel()
		{
			LoginCommand = new Command(() =>
			{
				//Login
				Login();
			});
		}
		private string id;
		public string Id
		{
			get => this.id;
			set
			{
				this.id = value;
				OnPropertyChanged(nameof(Id));
				OnPropertyChanged(nameof(resultData));
			}
		}

		private string password;
		public string Password
		{
			get => this.password;
			set
			{
				this.password = value;
				OnPropertyChanged(nameof(Password));
				OnPropertyChanged(nameof(resultData));
			}
		}

		private bool isBusy = false;
		public bool IsBusy
		{
			get => this.isBusy;
			set
			{
				this.isBusy = value;
				OnPropertyChanged(nameof(IsBusy));
			}
		}

		public string resultData
		{
			get => "아이디는 " + this.Id + "이고, 비밀번호는 " 
            		+ this.Password + "입니다.";
		}
		
		public ICommand LoginCommand { protected set; get; }
		
		private async void Login()
		{
			try
			{
				IsBusy = true;
				await Task.Delay(1000);
				IsBusy = false;
			}
			catch(Exception ex)
			{
				Console.WriteLine("Error : " + ex.ToString());
			}
		}
	}
}

LoginViewModel에서는 BaseViewModel을 상속받아 Id, Password, resultData에 대한 바인딩을 구성하였고, Login처리를 위한 메소드도 구현하였습니다. Binding에 대한 테스트를 위하여 실제와는 상관 없는 resultData를 구성하여, 실제 아이디와 비밀번호 입력시 resultData가 어떻게 변하는지 보이기 위해 추가하였습니다.

LoginCommand는 Login메소드를 실행 하기 위해 구현을 하였고, Login버튼 클릭시 구현하기 위해 Command로 작성하였습니다. Login메소드는 IsBusy를 True로 그리고 1초 대기 후 False로 변경하는 로직을 작성하였습니다. ActivityIndicator 동작을 위하여 구현을 하였습니다. ActivityIndicator는 Loading을 보여주는 기능이라고 보시면됩니다. 

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:mv="clr-namespace:test.ViewModel"
             x:Class="test.MainPage">
    <ContentPage.BindingContext>
        <mv:LoginViewModel/>
    </ContentPage.BindingContext>
    <StackLayout>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="50"/>
                <RowDefinition Height="50"/>
                <RowDefinition Height="50"/>
                <RowDefinition Height="50"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <Entry Grid.Row="0"
                   Text="{Binding Id,Mode=TwoWay}"
                   Placeholder="ID"/>
            <Entry Grid.Row="1"
                   Text="{Binding Password,Mode=TwoWay}"
                   Placeholder="Password"
                   IsPassword="True"/>
            <Button Grid.Row="2"
                    Text="Login"
                    Command="{Binding LoginCommand}"/>
            <Label Grid.Row="3"
                   Text="{Binding resultData}"/>
            <ActivityIndicator Grid.Row="4"
                               IsRunning="{Binding IsBusy}"
                               IsVisible="{Binding IsBusy}"/>
        </Grid>
    </StackLayout>

</ContentPage>

MainPage에서 ContentPage.Binding을 하여 위에서 작성한 ViewModel을 바인딩 작업을 진행합니다. 그리고 나머지 객체에 데이터를 바인딩합니다. 위 LoginViewModel 에서 작성한 Id, Password,resultData는 각각 Entry와 Label에 Binding하여 구현되었습니다. 그리고 LoginCommand는 Button에 Command에 바인딩 하였습니다. 그리고 마지막으로 ActivtyIndicator에 IsBusy를 구현하여 동작중인 모습을 구현하였습니다. 테스트 결과는 아래에 캡쳐와 동영상을 첨부하였습니다.

 

결과

결과 동영상

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ID와 Password를 입력시 아래에 라벨에 데이터가 변경되는 것을 확인 할 수 있습니다. 그리고, Login버튼을 눌렀을때 Loading되는 기능을 확인 하실수 있습니다.  기본적인 MVVM 패턴에 관하여 알아봤습니다. 궁금하신 내용은 댓글 또는 메일을 주시면 답변 드리도록 하겠습니다. 감사합니다.

728x90
반응형

'.NET > Xamarin' 카테고리의 다른 글

[Xamarin] Entry 숫자만 적용  (0) 2023.01.06
Comments