2022. 8. 22. 00:00ㆍMAUI
지금 까지 Xaml 을 작업하면서 약간의 불편을 느꼈을 것이다.
못느꼈을수도 있다. (😂)
어쨌는 Xaml 을 사용하여 작업하는 것은 많은 이점이 있고 편리함을 주지만
MVVM 형태로 작업할 때 ViewModel 을 통해 연결 하게 되면 몇가지 문제점을 발견하게 된다.
- 첫번째 ViewModel 에 존재하지 않는 property 나 command 를 컴파일 타임에 발견하지 못한다.
- 두번째 복잡한 UI 를 개발 하게 되면 Xaml 에 속도가 만족할 만큼 나오지 않는다고 생각할 수 있다.
위와 같은 두가 지 문제를 해결해 보자
일단 지금 첫번째 문제인 컴파일 타임에 Xaml 의 Binding 관련 오류를 발견해보자
생각보다 아주 간단하게 처리 할 수 있다.
x:DataType="viewmodel"
위의 한줄로 처리 가능 하다.
이전 강좌에서 사용했던 IncrementCounterPage.xaml 과 IncrementCounterViewModel.cs 를 확인해 보자
IncrementCounterPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MauiApp1.MVVM.AutoScan.IncrementCounterPage"
xmlns:local="clr-namespace:MauiApp1.MVVM.AutoScan"
x:DataType="local:IncrementCounterViewModel"
Title="IncrementCounterPage">
<VerticalStackLayout>
<Label Text="{Binding Counter, Mode=OneWay}"/>
<Button
Text="Click me!"
Command="{Binding IncrementCounterCommand}"/>
<Label Text="{Binding Message, Mode=OneWay}"/>
<Label Text="{Binding Message2, Mode=OneWay}"/>
<Button
Text="Change message"
Command="{Binding ChangeMessageCommand}"/>
</VerticalStackLayout>
</ContentPage>
x:DataType="local:IncrementCounterViewModel"
위를 이용하여 처리 가능 하다
IncrementCounterViewModel.cs
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using MauiApp1.InjectableServices;
namespace MauiApp1.MVVM.AutoScan;
public partial class IncrementCounterViewModel : ObservableObject, ITransientService
{
public IncrementCounterViewModel(IHelloWorldClass helloWorld)
{
_helloWorld = helloWorld;
}
[ObservableProperty]
private int _counter;
[ObservableProperty]
private string _message;
private readonly IHelloWorldClass _helloWorld;
[RelayCommand]
private void IncrementCounter() => Counter++;
[RelayCommand]
private void ChangeMessage()
{
Message = _helloWorld.Execute();
}
}
IncrementCounterPage.xaml.cs
using MauiApp1.InjectableServices;
namespace MauiApp1.MVVM.AutoScan;
public partial class IncrementCounterPage : ContentPage, ITransientService
{
public IncrementCounterPage(IncrementCounterViewModel incrementCounterViewModel)
{
InitializeComponent();
BindingContext = incrementCounterViewModel;
}
}
이렇게 하고 컴파일 하게 되면 Message2 를 찾을 수 없다는 오류가 나오게 된다.
x:DataType 을 xaml 에서 제거하면 오류는 나오지 않는다.
하지만 실제 runtime 시에 label 에는 아무 표시도 되지 않는다. 이러한 문제를 해결하기 위해서 x:DataType 을 활용하자
그리고 두번째 문제인 performance 을 처리 해보자
이문제는 IncrementCounterPage.xaml.cs 의 class 정의 상단에 다음과 같은 문구를 넣어 처리 가능 하다.
[XamlCompilation(XamlCompilationOptions.Compile)]
using MauiApp1.InjectableServices;
namespace MauiApp1.MVVM.AutoScan;
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class IncrementCounterPage : ContentPage, ITransientService
{
public IncrementCounterPage(IncrementCounterViewModel incrementCounterViewModel)
{
InitializeComponent();
BindingContext = incrementCounterViewModel;
}
}
만약 전체 Xaml 에 대 적용하고 싶다면 assembly 수준에서 정의하면 된다.
[assembly: XamlCompilation(XamlCompilationOptions.Compile)]
App.xaml.cs 파일로 이동하여 다음을 namespace 상단에 정의하자
이와 같이 정의 하면 같은 assembly 안에 있는 모든 Xaml page 는 Compile 과정을 거쳐 처리된다.
그런데 Roslyn 같은 runtime code generator 가 가능한 기술을 사용하여 ViewModel 을 생성하는 경우도 생각해 볼수 있다.
이런 경우에는 viewmodel 을 동적으로 생성하기 때문에 compile time 에 error 를 검출해서는 안된다.
그럴경우를 위해 특정 page 만 skip 하도록 option 을 줄수 있다.
XamlCompilationOptions.Skip 이 바로 그 작업을 수행한다.
이러한 내용을 통해 assembly 또는 page 수준에서 XamlCompilationOption 을 설정하여 performace 를 높일 수 있다.
관련영상
'MAUI' 카테고리의 다른 글
.NET MAUI - CommunityToolkit.Maui 유용한 Behavior 1 (0) | 2022.08.24 |
---|---|
.NET MAUI - CommunityToolkit.Maui and Alerts (0) | 2022.08.23 |
.NET MAUI - MVVM Dependency Injection 2/2 (AutoScan with Scrutor) (0) | 2022.08.19 |
.NET MAUI - MVVM Dependency Injection 1/2 (0) | 2022.08.18 |
.NET MAUI - MVVM SourceGenerator (0) | 2022.08.17 |