티스토리 뷰
2022.09.06 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내v1.0 part9-2 StyleSelector
2022.08.31 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 v1.0 part9-1 DataTemplateSelector
2022.08.08 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 v1.0 part8-3 Template
2022.08.02 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 v1.0 part8-2 Template
2022.07.21 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 v1.0 part8-1 Template
2022.07.13 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 v1.0 part7 Behavior
2022.07.05 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 V1.0 part6 Command
2022.06.27 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 V1.0 part5 Converter
2022.06.15 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 V1.0 part4-2 Data Binding
2022.06.13 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 V1.0 part4-1 Data Binding
2022.06.07 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 V1.0 part3-3
2022.06.02 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 V1.0 part3-2
2022.05.30 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 V1.0 part3-1
2022.05.11 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 v1.0 part2
2022.05.09 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 v1.0 part1
2021.02.18 - [UWP & Windows App/Beginner] - MVVM Pattern을 사용하는 개발자를 위한 안내 (업데이트 : 2022/03/21)
제 블로그에서 가장 인기있는 포스팅이 바로 MVVM Pattern 관련 포스팅입니다. 그런데, 오래전에 등록한 포스팅이라 이번에 새롭게 WPF 버전으로 정리를 하려고 합니다.
1. MVVM Pattern History
- MVVM은 WPF (Windows Presentation Foundation) 및 Silverlight의 기능을 활용하여 이벤트 중심 프로그래밍을 간소화하기 위해 Microsoft 아키텍처 Ken Cooper 및 Ted Peters가 개발했습니다.
- Microsoft의 WPF 및 Silverlight 아키텍트 중 한 명인 John Gossman은 2005 년 자신의 블로그에서 MVVM에 대한 내용을 포스팅 했습니다.
- MVVM Model View ViewModel Part - 1
2. Motivation for the MVVM Pattern
- Event-driven architecture 사용 응용 프로그램을 오랜 기간 유지보수하고 관리를 했을 때 발생되는 문제점 해결이 필요했습니다.
- 코드의 복잡성 상승 문제
- UI 수정 난이도 상승
- 중복코드 발생 - 기존 코드를 수정하지 않고, 복사해서 새로 만들어 사용
- Unit Test를 할 수 없음
- 비지니스 로직만 인스턴스 할 수 없음
- 메모리 관리의 어려움
- 전체적인 성능 저하
- 최신 기술 도입 어려움
- Advantages and Disadvantages of Event-Driven Programming
3. The MVVM Pattern
- 뷰, 뷰모델, 모델은 분리된 구성 요소
- 대체 가능해야 함
- 수정 시 다른 요소에 영향을 주지 않아야 함
- 독립적인 작업이 가능해야 함
- 격리 Unit test가 가능해야 함
- Data Binding and Command 구성 요소
- Binding
- ICommand
- Send Notifications 구성 요소
- INotifyPropertyChanged
- INotifyCollectionChanged
4. View
- 사용자가 보는 화면(구조, 레이아웃 및 모양)을 정의하는 역할을 담당합니다.
- View는 비즈니스 로직을 포함하지 않고, 제한된 code-behind만 사용하며, 순수하게 XAML로만 정의 됩니다.
- WPF, UWP에서 View는 Window, Page, UserControl을 사용하나, Xamarin.Forms에서는 forms:WindowsPage, .NET MAUI에서는 ContentPage를 사용합니다.
- 자신만의 뷰모델을 사용하거나, 상위 뷰모델을 상속받아 사용하고, 뷰모델의 변경 알림 이벤트(INotifyPropertyChanged)에 응답해서 뷰를 변경합니다.
예) MainWindow.xaml
<Window x:Class="CoreWpf.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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:local="clr-namespace:CoreWpf"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Button Content="GetWindowRectangle" Command="{Binding GetCommand}"/>
<TextBlock x:Name="Result"/>
</StackPanel>
</Grid>
</Window>
5. Model
- 비즈니스 및 유효성 검사 로직과 함께 데이터 모델을 포함하는 응용 프로그램의 도메인 모델을 이야기합니다.
- 모델은 대부분 class로 만들어지며, 내부에 property를 가지고 있습니다.
- 예) Repositories, business objects, data transfer objects(DTOs), Plain Old CLR Objects(POCOs)
- INotifyPropertyChanged 이벤트와 TwoWay Binding을 이용해서 View와 양방향 데이터 송수신을 할 수 있습니다.
- 가능한 비즈니스 로직을 포함하지 않도록 작성합니다.
예) Person.cs
using Microsoft.Toolkit.Mvvm.ComponentModel;
namespace BasicControlSample
{
public class Person : ObservableObject
{
private string _name;
public string Name
{
get { return _name; }
set { SetProperty(ref _name, value); }
}
private bool _sex;
public bool Sex
{
get { return _sex; }
set { SetProperty(ref _sex, value); }
}
private int _age;
public int Age
{
get { return _age; }
set { SetProperty(ref _age, value); }
}
private string _address;
public string Address
{
get { return _address; }
set { SetProperty(ref _address, value); }
}
}
}
6. ViewModel
- View와 Model 사이의 중개자 역할을 하며, View의 동작을 상태(Status)를 이용해 제어 합니다.
- 여러개의 Model을 목록형으로 제공하면, View의 컨트롤이 이를 사용자에게 보여줍니다.
- View에 Add버튼을 클릭하면, ICommand를 이용해서, 메소드를 실행 시키고, 메소드에서 데이터 목록에 새로운 Model을 추가합니다.
- INotifyPropertyChanged 이벤트와 TwoWay Binding을 이용해서 View와 양방향 데이터 송수신을 할 수 있습니다.
-
서비스들을 이용해서 비즈니스 로직을 처리합니다.
예) MainViewModel.cs
using Microsoft.Toolkit.Mvvm.ComponentModel;
using Microsoft.Toolkit.Mvvm.Input;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
namespace BasicControlSample
{
public class MainViewModel : ObservableObject
{
private IList<Person> _persons = new ObservableCollection<Person>
{
new Person{ Name = "kaki0104", Sex = true, Age = 11, Address = "Seoul1" },
new Person{ Name = "kaki0143", Sex = false, Age = 150, Address = "Seoul140" },
};
public IList<Person> Persons { get { return _persons; } }
private Person _selectedListItem;
public Person SelectedListItem
{
get { return _selectedListItem; }
set { SetProperty(ref _selectedListItem, value); }
}
private Person _selectedComboItem;
public Person SelectedComboItem
{
get { return _selectedComboItem; }
set { SetProperty(ref _selectedComboItem, value); }
}
private Person _selectedListItem2;
public Person SelectedListItem2
{
get { return _selectedListItem2; }
set { SetProperty(ref _selectedListItem2, value); }
}
public IRelayCommand DeleteListItemCommand { get; set; }
private Person _selectedComboItem2;
public Person SelectedComboItem2
{
get { return _selectedComboItem2; }
set { SetProperty(ref _selectedComboItem2, value); }
}
public IRelayCommand DeleteComboItemCommand { get; set; }
public MainViewModel()
{
Init();
}
private void Init()
{
SelectedListItem = Persons.FirstOrDefault();
SelectedComboItem = Persons.FirstOrDefault();
DeleteListItemCommand = new RelayCommand(OnDeleteListItem,
() => SelectedListItem2 != null && SelectedListItem2.Age % 2 == 0);
DeleteComboItemCommand = new RelayCommand(OnDeleteComboItem,
() => SelectedComboItem2 != null && SelectedComboItem2.Age % 2 == 1);
}
private void OnDeleteComboItem()
{
Persons.Remove(SelectedComboItem2);
}
private void OnDeleteListItem()
{
Persons.Remove(SelectedListItem2);
}
}
}
7. The Benefits of MVVM
- 관심사의 분리(Separation of concerns)를 이용하여 문제를 해결할 수 있습니다.
- 코드의 복잡성 축소, UI 수정 난이도 하락, 메모리 관리 용이, 전체적인 성능 향상, 최신 기술 도입 용이
- ViewModel과 Model은 개발자가, View는 디자이너가 각자 동시 작업이 가능합니다.
- 개발자는 UI(View)없이 ViewModel을 인스턴스시켜 Unit Test 프로젝트를 생성하고 테스트할 수 있습니다.
8. Platform별 차이점(2022-04-26)
구분 | WPF | UWP | Xamarin.Forms | Uno Platform | .NET MAUI | Windows App SDK |
Windows 10, 11 | O | O | O | O | O | O |
Android | X | X | O | O | O | X |
iOS, macOS | X | X | iOS | O | O | X |
Support OS | Linux, Tizen | |||||
WPF XAML | O | O | △ | O | △ | O |
Windows 7 | O | X | O | O | X | X |
안정성 | Stable | Stable | Stable | Stable | Preview | Experimental |
Sandbox | X | O | ? | UWP:O, WPF:X | ? | X |
9. 화면 개발자 vs 공통 개발자
- MVVM Pattern을 사용하는 화면 개발자
- MVVM 기본 개념 파악하고(Binding, Template, ICommand) 이미 만들어져있는 다른 화면을 참고하면서 개발
- IValueConverter나 CustomControl 등 고급 기능이 필요한 경우 공통 개발자(팀)에 문의 후 사용
- 비지니스 로직을 이해하고 구현하는것이 목표
- MVVM Pattern을 사용하는 Framework(공통) 개발자
- MVVM Pattern의 모든 기능을 이해하고, 개발할 수 있어야 함
- IValueConver, Behavior, IoC Container, Dependency Injection, Custom Control, Style, Animation, Selector 등
- 화면 개발자들이 빠르게 개발을 진행할 수 있게 서포트를 하면서, 성능 이슈가 발생하지 않도록 코드를 정규화 시켜야 함
10. Q&A
- Q1. MVVM Pattern을 꼭 사용해야 하나요?
- A1. XAML을 사용하는 플랫폼에서는 사용하는 것을 권장합니다.
- Q2. 코드 비하인드(code-behind)에 코딩을 하지 못하나요?
- A2. 코딩을 할 수 있고, 일부 코딩이 필요하기도 합니다. 하지만, MVVM Pattern은 View와 ViewModel이 서로 의존성을 가지지 않도록 개발하기 때문에 거의 필요도 없고, 추천하지 않습니다.
- Q3. View의 Button_Click 이벤트를 생성하고, 코드 비하인드에서 화면을 열거나 간단한 동작등은 처리해도 괜찮나요?
- A3. 코드 비하인드에 코딩은 추천하지 않습니다. ViewModel이 해당 화면에 대한 모든 논리를 담당해야하는데, 나누어져있다면 코드 복잡도가 상승하여 운영시에 문제가 발생할 수 있습니다.
- Q4. 개발 속도는 어떤가요?
- A4. WinForm의 Event-driven 방식에 비해서 1.5배 정도는 느립니다. 하지만, 화면 개발자가 익숙해지면 큰 차이는 없을 것이라고 생각됩니다.
- Q5. View나 Control을 ViewModel에서 직접 제어하면 않되나요?
- A5. 네. 그렇게 사용하시면 View와 ViewModel의 의존성이 생기기 때문에 사용하시면 않됩니다.
- Q6. View나 Control의 모든 기능을 ViewModel에서 제어가 가능한가요?
- A6. ViewModel은 화면의 논리적인 부분을 담당하고, 각 컨트롤들의 제어는 논리를 기준으로 처리되어야 합니다. 컨트롤을 복잡하게 제어해야하는 경우에는 Behavior나 Custom Control 등을 이용하면 어떤 화면이든지 만들 수 있습니다.
11. 참고
- Microsoft.Toolkit.Mvvm을 이용한 간단한 프레임워크
- The MVVM Pattern(영문)
- MVVM Pattern(오래전에 만든 동영상)
- Todo list Universal & UWP app(블로그)
- [교안 공유] WPF XAML MVVM에서부터 Prism,Reactive(Rx) Framework 개발(All Coding 과정)
'WPF .NET' 카테고리의 다른 글
Dependency Inversion Principle(DIP) - 의존성 역전 원칙 part1 (2) | 2022.05.19 |
---|---|
MVVM Pattern을 사용하는 개발자를 위한 안내 v1.0 part2 (18) | 2022.05.11 |
Microsoft.Toolkit.Mvvm을 이용한 간단한 프레임워크 part6 - 유효성 검사 추가 (2) | 2022.04.21 |
Syncfusion Metro Studio 5으로 아이콘 쉽게 만들어서 사용하기 (0) | 2022.04.18 |
Microsoft.Toolkit.Mvvm을 이용한 간단한 프레임워크 part5 - [ObservableProperty] 속성(2/2) (2) | 2022.04.15 |
- Total
- Today
- Yesterday
- uno platform
- Windows 10
- visual studio 2019
- #prism
- IOT
- #Windows Template Studio
- Always Encrypted
- LINQ
- Build 2016
- Cross-platform
- ef core
- C#
- XAML
- windows 11
- UWP
- Visual Studio 2022
- WPF
- kiosk
- .net
- #uwp
- .net 5.0
- Microsoft
- PRISM
- #MVVM
- uno-platform
- Bot Framework
- ComboBox
- dotNETconf
- MVVM
- Behavior
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |