[Avalonia] MVVM / View - ViewModel 연결

ADHD·2024년 5월 29일
post-thumbnail

- 개요

| MVVM 의 이해
| MVVM 패턴으로 TCP 신호 수신 기능을 적용해보며 역할 분리
| View - ViewModel 연결

- 내용

  1. MVVM
  2. View / ViewModel
    A. 참조
    B. DataContext 바인딩
    C. Main View 의 객체
    D. 하위 컴포넌트의 데이터 바인딩

1. MVVM

  • View - ViewModel - Model 로 기능적 분리를 해놓은 패턴
  • 개념에 대해 찾아보면 죄다 직역글만 복사해두고 현실세계와 연결된 비즈니스 로직이 어쩌고 해서 그냥 요약해둠
  • View
    Server 에 Message 를 보내는 그냥 Button UI
  • ViewModel
    View 의 Button 에 연결되어 있는 Func()
    Model 의 Func() 을 호출하는 기능
  • Model
    Message 를 전송하는 기능의 Func()

2. View / ViewModel

  • 진행중인 View 의 MainWindow.axaml 를 예로 Binding 에 필수 항목들
<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        
        xmlns:view="clr-namespace:Launcher.Views"
        xmlns:vm="using:Launcher.ViewModels"
        mc:Ignorable="d"
        x:Class="Launcher.Views.MainWindow"
        x:DataType="vm:MainWindowViewModel"
        
        Title="MainWindow"
        Width="800" Height="450">

	<StackPanel>
		<view:SelectFileView DataContext="{Binding SelectFileViewModel}" />
		<view:NetworkView DataContext="{Binding NetworkViewModel}" Margin="0,20,0,0"/>
	</StackPanel>
</Window>

A. 참조

  • clr-namespace / using 은 아무거나 사용 가능하나 주로 clr-namespace 는 View 나 단순 Class 의 namespace 를 가져올때 사용하고 using 은 .Net 관련 라이브러리나 ViewModel 의 namespace 를 적용 시 사용
  • MainWindow.axaml 에 가져와 사용할 View 의 namespace 를 적용
xmlns:view="clr-namespace:Launcher.Views"
  • MainWindow.axaml 에 가져와 사용할 ViewModel 의 namespace 적용
xmlns:vm="using:Launcher.ViewModels"
  • MainWindow.axaml 를 읽고 실행시키는 비하인드 클래스 적용
x:Class="Launcher.Views.MainWindow"
  • 가져온 View 에 바인딩 시킬 데이터 속성 지정
x:DataType="vm:MainWindowViewModel"

B. DataContext 바인딩

  • React 의 props 처럼 자식 컴포넌트에 객체를 보내는 방식과 유사하게 하위 View Class 에 DataContext 를 Binding
  • 진행중인 MainWindow.axaml 에는 파일 선택기능을 호출하는 SelectFileViewModelSelectFileView 에 Binding 하였고 TCP 연결과 메세지 기능을 호출하는 NetworkViewModelNetworkView 에 Binding
<view:SelectFileView DataContext="{Binding SelectFileViewModel}" />
<view:NetworkView DataContext="{Binding NetworkViewModel}" Margin="0,20,0,0"/>

C. Main View 의 객체

  • MainWindow.axaml 에서 위 과정으로 참조 및 바인딩 한 MainWindowViewModel.cs 의 내용
namespace Launcher.ViewModels
{
    public class MainWindowViewModel : ViewModelBase
    {
        public MainWindowViewModel()
        {
            NetworkViewModel = new NetworkViewModel();
            SelectFileViewModel = new SelectFileViewModel();
        }

        public NetworkViewModel NetworkViewModel { get; }
        public SelectFileViewModel SelectFileViewModel { get; }
    }
}
  • 위 [ B. DataContext ] 에서 사용 될 DataContext 를 사전 정의하여 MainWindowViewModel.cs 에 객체 생성을 해두어야 아래 [ D. 하위 컴포넌트의 데이터 바인딩 ] 처럼 실제 데이터들이 사용 가능해진다.

D. 하위 컴포넌트의 데이터 바인딩

  • MainWindow.axaml 에 자식 컴포넌트로 들어간 NetworkView.axaml 에서 바인딩으로 데이터를 받고 있는 코드
<UserControl xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:vm="using:Launcher.ViewModels"
             mc:Ignorable="d"
             x:Class="Launcher.Views.NetworkView"
             x:DataType="vm:NetworkViewModel">

	<StackPanel>
		<TextBlock Text="Log:" />
		<TextBox Text="{Binding Log}" IsReadOnly="True" AcceptsReturn="True" Height="100" />
		<Button Command="{Binding ConnectCommand}" Content="Connect" />
		<Button Command="{Binding SendMessageCommand}" Content="Send Message" />
	</StackPanel>
</UserControl>
  • [ C. Main View 의 객체 ] 에서 데이터가 담긴 클래스를 객체화 하여 바인딩으로 하위 컴포넌트에 내려줬기 떄문에 하위 컴포넌트인 NetworkView.axaml 에서 NetworkViewModel.cs 의 각 항목들에 대해 데이터 바인딩이 가능하다.

0개의 댓글