[C#] WPF MVVM 메모장 만들기 강좌

2026. 7. 9. 20:52·Programming/C#.NET

이번 강좌에서는 단순 이벤트 기반 메모장이 아니라, 실무에서 가장 많이 사용하는 MVVM(Model-View-ViewModel) 패턴으로 메모장을 만들어 보겠습니다.

 

MVVM이란?

WPF에서 UI와 비즈니스 로직을 분리하기 위한 패턴입니다.

기존 방식

View(XAML)
    ↓
Code Behind

 

MVVM 방식

View
 ↓
ViewModel
 ↓
Model

 

구조

MemoProject
│
├─ Models
│   └─ MemoModel.cs
│
├─ ViewModels
│   └─ MainViewModel.cs
│
├─ Commands
│   └─ RelayCommand.cs
│
└─ Views
    └─ MainWindow.xaml

 

Model 만들기

Models/MemoModel.cs

namespace MemoProject.Models
{
    public class MemoModel
    {
        public string Content? { get; set; }
    }
}

 

Model은 데이터만 보관합니다.

 

RelayCommand 만들기

MVVM에서는 Button Click 대신 Command를 사용합니다.
Commands/RelayCommand.cs

using System;
using System.Windows.Input;

namespace MemoProject.Commands
{
    public class RelayCommand(Action execute) : ICommand
    {
        private readonly Action _execute = execute;

        public bool CanExecute(object? parameter)
        {
            return true;
        }

        public void Execute(object? parameter)
        {
            _execute();
        }

        public event EventHandler? CanExecuteChanged;
    }
}

 

ViewModel 만들기

ViewModels/MainViewModel.cs

using MemoProject.Commands;
using Microsoft.Win32;
using System.ComponentModel;
using System.IO;
using System.Runtime.CompilerServices;
using System.Windows.Input;

namespace MemoProject.ViewModels
{
    public class MainViewModel : INotifyPropertyChanged
    {
        private string _memoText;

        public string MemoText
        {
            get => _memoText;
            set
            {
                _memoText = value;
                OnPropertyChanged();
            }
        }

        public ICommand NewCommand { get; }
        public ICommand SaveCommand { get; }
        public ICommand OpenCommand { get; }

        public MainViewModel()
        {
            NewCommand = new RelayCommand(NewMemo);
            SaveCommand = new RelayCommand(SaveMemo);
            OpenCommand = new RelayCommand(OpenMemo);
        }

        private void NewMemo()
        {
            MemoText = "";
        }

        private void SaveMemo()
        {
            SaveFileDialog dialog = new SaveFileDialog();

            dialog.Filter = "텍스트 파일|*.txt";

            if (dialog.ShowDialog() == true)
            {
                File.WriteAllText(
                    dialog.FileName,
                    MemoText);
            }
        }

        private void OpenMemo()
        {
            OpenFileDialog dialog =
                new OpenFileDialog();

            dialog.Filter = "텍스트 파일|*.txt";

            if (dialog.ShowDialog() == true)
            {
                MemoText =
                    File.ReadAllText(
                        dialog.FileName);
            }
        }

        public event PropertyChangedEventHandler? PropertyChanged;

        private void OnPropertyChanged(
            [CallerMemberName] string propertyName = "")
        {
            PropertyChanged?.Invoke(
                this,
                new PropertyChangedEventArgs(propertyName));
        }
    }
}

 

View(XAML) 작성

MainWindow.xaml

<Window x:Class="MemoProject.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MVVM 메모장"
        Height="450"
        Width="800">

    <DockPanel>

        <StackPanel Orientation="Horizontal"
                    DockPanel.Dock="Top"
                    Margin="5">

            <Button Content="새로 만들기"
                    Width="100"
                    Margin="5"
                    Command="{Binding NewCommand}"/>

            <Button Content="열기"
                    Width="100"
                    Margin="5"
                    Command="{Binding OpenCommand}"/>

            <Button Content="저장"
                    Width="100"
                    Margin="5"
                    Command="{Binding SaveCommand}"/>
        </StackPanel>

        <TextBox Text="{Binding MemoText,
                                UpdateSourceTrigger=PropertyChanged}"
                 AcceptsReturn="True"
                 AcceptsTab="True"
                 FontSize="15"
                 VerticalScrollBarVisibility="Auto"
                 HorizontalScrollBarVisibility="Auto"/>
    </DockPanel>

</Window>

 

ViewModel 연결하기

MainWindow.xaml.cs

using MemoProject.ViewModels;
using System.Windows;

namespace MemoProject
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            DataContext =
                new MainViewModel();
        }
    }
}

 

데이터 바인딩 이해하기

이 부분이 MVVM의 핵심입니다.

<TextBox Text="{Binding MemoText}" />

 

동작 과정

사용자 입력
      ↓
TextBox
      ↓
MemoText 속성
      ↓
ViewModel

 

반대로

ViewModel
      ↓
MemoText 변경
      ↓
UI 자동 변경

 

즉 UI와 코드가 직접 연결되지 않습니다.

 

글자 수 표시 기능 추가

ViewModel

public int CharacterCount
{
    get => MemoText?.Length ?? 0;
}

 

MemoText 수정

set
{
    _memoText = value;

    OnPropertyChanged();
    OnPropertyChanged(nameof(CharacterCount));
}

 

XAML

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

 

MVVM 방식의 장점

이벤트 코드가 없음

기존

Click="Button_Click"

 

MVVM

Command="{Binding SaveCommand}"

 

테스트 가능

viewModel.SaveCommand.Execute(null);

 

버튼 없이도 테스트 가능 디버깅 창에서 위 명령어를 실행하면 Test

 

유지보수 쉬움

View
 ↕
Binding
 ↕
ViewModel
 ↕
Model

 

각 역할이 명확합니다.

'Programming > C#.NET' 카테고리의 다른 글

Prism Template Pack 소개  (0) 2026.07.22
C#에서 Dynamic하게 DLL의 Entity 타입 찾기 (AppDomain vs BuildManager)  (0) 2026.07.20
C# WPF MVVM이란? 유지보수가 쉬운 데스크톱 애플리케이션 개발 패턴  (0) 2026.07.08
[C#] WPF 기초 강좌 #3  (0) 2026.07.07
[C#] WPF 기초 강좌 #2  (0) 2026.07.05
'Programming/C#.NET' 카테고리의 다른 글
  • Prism Template Pack 소개
  • C#에서 Dynamic하게 DLL의 Entity 타입 찾기 (AppDomain vs BuildManager)
  • C# WPF MVVM이란? 유지보수가 쉬운 데스크톱 애플리케이션 개발 패턴
  • [C#] WPF 기초 강좌 #3
레이조(RayCho)
레이조(RayCho)
개발자 레이조(RayCho)의 블로그입니다. 똑똑하게 배우고 기록하는 공간
  • 레이조(RayCho)
    레이(Ray)의 개발이야기
    레이조(RayCho)
  • 전체
    오늘
    어제
    • 분류 전체보기 (101) N
      • Programming (101) N
        • Python (9)
        • Flutter (4)
        • Delphi (25)
        • Java,Spring Boot (2) N
        • Lazarus (2)
        • C#.NET (20)
        • ASP.NET (5)
        • Database (8)
        • Game Dev (6)
        • Rust (3)
        • PHP (3)
        • Web (6)
        • ETC (8)
  • 블로그 메뉴

    • 홈
    • Introduce
    • 태그
  • 링크

    • Naver Blog
    • Diary Blog
  • 공지사항

  • 인기 글

  • 태그

    문법
    델파이
    WPF
    Flutter
    VCL
    프로젝트
    PSP
    objectpascal
    iis
    소스코드
    csharp
    Web
    ASP.NET
    mssql
    기초
    delphi
    개발환경
    프로그래밍
    C#
    Python
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
레이조(RayCho)
[C#] WPF MVVM 메모장 만들기 강좌
상단으로

티스토리툴바