WPF MVVM 패턴, 그리고 Binding

안녕하세요! 오늘은 WPF (Windows Presentation Foundation)에서 Binding과 MVVM (Model-View-ViewModel) 패턴에 대한 이해를 도와드릴 예정입니다.
이 글을 통해 MVVM 패턴이 무엇인지, Binding이 어떻게 작동하는지, 그리고 MVVM과 어떻게 연결되는지 알아보겠습니다.


1. MVVM 패턴 소개

MVVM은 Model, View, ViewModel의 약자로, 세 부분으로 나뉩니다.


2. 왜 MVVM이 필요한가?

MVVM 패턴은 큰 프로젝트나 복잡한 UI를 가진 애플리케이션에서 매우 유용합니다.
예를 들어, 여러 개발자가 같은 프로젝트에 참여하고 있다면, MVVM을 사용하면 UI와 로직을 분리하여 작업할 수 있습니다.
이렇게 하면 코드의 재사용성이 높아지고 유지보수가 쉬워집니다.


예시: 쇼핑몰 앱

만약 MVVM을 사용하지 않는다면, 상품을 장바구니에 추가할 때마다 UI 코드 내에서 모든 것을 처리해야 할 것입니다.
이는 코드가 복잡해지고, 다른 개발자가 이해하기 어렵게 만듭니다.



3. MVVM 구현 예제 코드

Model

public class Product
{
    public string Name { get; set; }
    public double Price { get; set; }
}


ViewModel

ObservableCollection을 통해 위 Model을 관리하고 있습니다.

public class ShoppingCartViewModel : INotifyPropertyChanged
{
    private ObservableCollection<Product> _products;
    public ObservableCollection<Product> Products
    {
        get { return _products; }
        set
        {
            _products = value;
            OnPropertyChanged("Products");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

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

    public ICommand AddToCartCommand { get; private set; }

    public ShoppingCartViewModel()
    {
        Products = new ObservableCollection<Product>();
        AddToCartCommand = new RelayCommand(AddProductToCart);
    }

    private void AddProductToCart(object parameter)
    {
        // Add product to cart logic
    }
}


View (Xaml 코드)

<ListView ItemsSource="{Binding Products}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding Name}" />
                <TextBlock Text="{Binding Price}" />
            </StackPanel>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>
<Button Command="{Binding AddToCartCommand}" Content="Add to Cart" />


Data Context 설정

바인딩의 소스는 일반적으로 DataContext를 통해 설정됩니다.
이는 XAML 파일의 루트 요소 또는 특정 UI 요소에서 설정할 수 있습니다.

<Window x:Class="YourNamespace.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:ShoppingCartViewModel/>
    </Window.DataContext>
    
    <!-- Your UI here -->
</Window>



4. 갑자기 나타난 DataContext란 무엇인가?

DataContext는 WPF (Windows Presentation Foundation)에서 중요한 역할을 하는 프로퍼티 중 하나입니다.
이 프로퍼티는 바인딩의 기본 소스가 되며, 어떤 객체가 UI와 어떻게 연결될 것인지를 정의합니다.
DataContext는 상속될 수 있는 프로퍼티입니다. 즉, 부모 요소의 DataContext 설정이 자식 요소로 전파될 수 있습니다.


작동 원리

  1. 바인딩의 기본 소스 설정: WPF 바인딩 시스템에서는 Binding 객체의 Source 프로퍼티를 명시적으로 설정하지 않으면 자동으로 해당 요소의 DataContext를 바인딩 소스로 사용합니다.

  2. 계층적 상속: DataContext는 계층적으로 상속됩니다. 부모 요소에 DataContext가 설정되면, 그 설정은 자식 요소에게 상속됩니다. 이를 통해 ViewModel의 하위 객체를 UI의 하위 요소와 쉽게 바인딩할 수 있습니다.

  3. 값 변경 알림: DataContext는 일반적으로 INotifyPropertyChanged 인터페이스를 구현한 객체에 바인딩됩니다. 이렇게 하면 데이터가 변경될 때 UI에 자동으로 알릴 수 있습니다.


예제

예를 들어, 아래와 같이 MainWindow 클래스에 DataContext를 설정할 수 있습니다.

public MainWindow()
{
    InitializeComponent();
    this.DataContext = new YourViewModel();
}

이렇게 하면, XAML에서는 다음과 같이 간단하게 프로퍼티에 접근할 수 있습니다.

<TextBlock Text="{Binding YourProperty}" />

여기서 YourPropertyYourViewModel 클래스 내에 정의된 프로퍼티입니다.


주의 사항


이러한 방식으로 DataContext는 WPF의 바인딩 메커니즘에서 중심 역할을 하며, ViewModel과 View를 효과적으로 연결해 줍니다.



5. Binding이란?

Binding은 View와 ViewModel 사이의 데이터 연결을 담당합니다.
Binding을 통해 ViewModel의 변경사항이 자동으로 View에 반영되고, 반대로 View의 변경사항도 ViewModel에 자동으로 반영됩니다.



6. Binding의 내부 동작 방식

Binding이 어떻게 동작하는지를 이해하려면 여러 WPF의 특성과 기술을 알아야 합니다.
이 중에서도 두 가지 주요 기술이 있습니다: DependencyPropertyINotifyPropertyChanged.


DependencyProperty

DependencyProperty는 WPF에서 제공하는 특별한 종류의 프로퍼티입니다. 이 프로퍼티는 자동으로 값의 변경을 감지하고, 변경이 일어나면 연결된 UI 요소를 업데이트합니다.


예시 코드 (Xaml)

<TextBlock x:Name="textBlock1" Text="{Binding ElementName=textBox1, Path=Text}" />
<TextBox x:Name="textBox1" Text="Hello, WPF!" />

이 코드에서 TextBlockText 프로퍼티는 TextBoxText 프로퍼티에 바인딩됩니다.
Text 프로퍼티는 DependencyProperty이므로, TextBox의 텍스트가 변경되면 TextBlock도 자동으로 업데이트됩니다.


INotifyPropertyChanged

INotifyPropertyChanged 인터페이스는 ViewModel에서 주로 사용되며, 프로퍼티의 값이 변경될 때 PropertyChanged 이벤트를 발생시켜 UI에 알려줍니다.


예시 코드 (ViewModel)

public class MainViewModel : INotifyPropertyChanged
{
    private string _userName;
    public string UserName
    {
        get { return _userName; }
        set
        {
            _userName = value;
            OnPropertyChanged("UserName");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

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


예시코드 (Xaml)

<TextBlock Text="{Binding UserName}" />

이 코드에서 ViewModel의 UserName 프로퍼티가 변경되면 PropertyChanged 이벤트가 발생하고, 이에 따라 바인딩된 TextBlockText 프로퍼티가 업데이트됩니다. 이렇게 DependencyPropertyINotifyPropertyChanged를 이용하면, WPF에서 데이터 바인딩이 어떻게 내부적으로 동작하는지 이해할 수 있습니다.



7. 마치며

WPF의 데이터 바인딩은 코드와 UI의 분리, 자동 업데이트, 표준화 및 재사용성 등 여러 목적을 위해 설계되었습니다.
내부 동작 방식은 복잡해 보이지만, 이를 이해하고 적절히 활용한다면 강력하고 효율적인 애플리케이션을 개발할 수 있습니다.
이 글을 통해 바인딩의 목적과 내부 동작 방식에 대한 깊은 이해를 얻었길 바랍니다.






정규표현식의 유용한 패턴
#집합찾기 #반복찾기 #역참조 #조건달기
A 액티비티에서 B 액티비티로 데이터 전달하기
#WorkflowFoundation #InArgument #OutArugment #Variables
Microsoft UI Automation Framework 이해하기
#AutomationElement #TreeWalker #ControlPatterns
AppDomain 탐구
#AppDomain #격리 #어셈블리별도실행 #플러그인시스템
Chrome Extension 활용하여여 웹 페이지 XPath 정보 가져오기
#ChromeExtension #크롬확장프로그램 #XPath
Workflow 디자이너와 액티비티의 관계
#WorkflowFoundation #Designer #Activity #ModelItem
ExpressionTextBox와 ModelItem의 바인딩 관계
#WorkflowFoundation #ExpressionTextBox #ModelItem #Binding
Windows 레지스트리 간단 정리
#Windows #Registry #레지스트리
WPF MVVM 패턴, 그리고 Binding
#WPF #MVVM #Binding #Modle #View #ViewModel
오라클 SQL 성능 최적화 - 바인드 변수와 Shared Memory 이해하기
#Oracle #바인드변수 #SharedMemory #LibraryCache #SqlPlan
ActivityDesigner와 CodeActivity 이해하기
#WorkflowFoundation #ActivityDesigner #CodeActivity
Selenium Implicit vs Explicit - 웹 요소 기다리기
#Selenium #IWebDriver #Implicit #Explicit
.NET에서 Selenium 활용하기 - 3가지 실전 예제
#Selenium #ChromeDriver #FindElements
.NET에서 CommandBinding 활용하기
#.NET #CommandBinding #디자인패턴
워크플로우 파운데이션(Workflow Foundation) 소개
#WorkflowFoundation #소개 #기본개념
AWS SAA 준비 - (4) 비용에 최적화된 아키텍처 설계
(정리) Exam Readiness - AWS Solutions Architect Associate
AWS SAA 준비 - (3) 안전한 아키텍처
(정리) Exam Readiness - AWS Solutions Architect Associate
AWS SAA 준비 - (2) 성능이 뛰어난 아키텍처 설계
(정리) Exam Readiness - AWS Solutions Architect Associate
AWS SAA 준비 - (1) 복원력을 갖춘 아키텍처 설계
(정리) Exam Readiness - AWS Solutions Architect Associate
15분 안에 ToC를 구현해보자!
Vanilla JS로 Table of Contents 구현하기
모듈
모던 자바스크립트 Deep Dive | 48장 | 모듈
에러 처리
모던 자바스크립트 Deep Dive | 47장 | 에러 처리
제너레이터와 async/await
모던 자바스크립트 Deep Dive | 46장 | 제너레이터와 async/await
프로미스
모던 자바스크립트 Deep Dive | 45장 | 프로미스
REST API
모던 자바스크립트 Deep Dive | 44장 | REST API
Ajax
모던 자바스크립트 Deep Dive | 43장 | Ajax
비동기 프로그래밍
모던 자바스크립트 Deep Dive | 42장 | 비동기 프로그래밍
타이머
모던 자바스크립트 Deep Dive | 41장 | 타이머
Set과 Map
모던 자바스크립트 Deep Dive | 37장 | Set과 Map
디스트럭처링
모던 자바스크립트 Deep Dive | 36장 | 디스트럭처링
브라우저의 렌더링 과정
모던 자바스크립트 Deep Dive | 38장 | 브라우저의 렌더링 과정
스프레드 문법
모던 자바스크립트 Deep Dive | 35장 | 스프레드 문법
이터러블
모던 자바스크립트 Deep Dive | 34장 | 이터러블
7번째 데이터 타입 Symbol
모던 자바스크립트 Deep Dive | 33장 | 7번째 데이터 타입 Symbol
String
모던 자바스크립트 Deep Dive | 32장 | String
RegExp
모던 자바스크립트 Deep Dive | 31장 | RegExp
Date
모던 자바스크립트 Deep Dive | 30장 | Date
Math
모던 자바스크립트 Deep Dive | 29장 | Math
DOM
모던 자바스크립트 Deep Dive | 39장 | DOM
Number
모던 자바스크립트 Deep Dive | 28장 | Number
배열
모던 자바스크립트 Deep Dive | 27장 | 배열
이벤트
모던 자바스크립트 Deep Dive | 40장 | 이벤트
ES6 함수의 추가 기능
모던 자바스크립트 Deep Dive | 26장 | ES6 함수의 추가 기능
클래스
모던 자바스크립트 Deep Dive | 25장 | 클래스
this
모던 자바스크립트 Deep Dive | 22장 | this
빌트인 객체
모던 자바스크립트 Deep Dive | 21장 | 빌트인 객체
strict mode
모던 자바스크립트 Deep Dive | 20장 | strict mode
클로저
모던 자바스크립트 Deep Dive | 24장 | 클로저
프로토타입
모던 자바스크립트 Deep Dive | 19장 | 프로토타입
함수와 일급 객체
모던 자바스크립트 Deep Dive | 18장 | 함수와 일급 객체
실행 컨텍스트
모던 자바스크립트 Deep Dive | 23장 | 실행 컨텍스트
생성자 함수에 의한 객체 생성
모던 자바스크립트 Deep Dive | 17장 | 생성자 함수에 의한 객체 생성
프로퍼티 어트리뷰트
모던 자바스크립트 Deep Dive | 16장 | 프로퍼티 어트리뷰트
let, const 키워드와 블록 레벨 스코프
모던 자바스크립트 Deep Dive | 15장 | let, const 키워드와 블록 레벨 스코프
전역 변수의 문제점
모던 자바스크립트 Deep Dive | 14장 | 전역 변수의 문제점
스코프
모던 자바스크립트 Deep Dive | 13장 | 스코프
함수
모던 자바스크립트 Deep Dive | 12장 | 함수
원시 값과 객체의 비교
모던 자바스크립트 Deep Dive | 11장 | 원시 값과 객체의 비교
객체 리터럴
모던 자바스크립트 Deep Dive | 10장 | 객체 리터럴
타입 변환과 단축 평가
모던 자바스크립트 Deep Dive | 9장 | 타입 변환과 단축 평가
제어문
모던 자바스크립트 Deep Dive | 8장 | 제어문
연산자
모던 자바스크립트 Deep Dive | 7장 | 연산자
데이터 타입
모던 자바스크립트 Deep Dive | 6장 | 데이터 타입
표현식과 문
모던 자바스크립트 Deep Dive | 5장 | 표현식과 문
변수
모던 자바스크립트 Deep Dive | 4장 | 변수
Iteration와 Generator
코드스피츠 77 ES6+ 3화 참조
WHATWG 탄생 배경
WHATWG, W3C, HTML의 관련에 대한 역사
프론트엔드(FE) 면접 질문 정리
FE관련 면접 질문 및 답변 정리한 내용입니다.
쿠버네티스(kubernetes, k8s) 용어 정리
쿠버네티스(kubernetes, k8s) 용어 정리
젠킨스(Jenkins) 정리
젠킨스(Jenkins) 정리
Docker 용어 정리
Docker 용어 정리
Git 용어 정리
Git 용어 정리
반응형 웹 디자인(Responsive Web Design)
CSS responsive 에 대하여
JS this에 대하여
this에 대해 알아보자
SQL*PLUS에 대하여
SQL*PLUS 정의 및 사용방법
Oracle에서 SQL Plan 확인하기
Oracle에서 SQL Plan을 확인해보자