본문 바로가기

[C# WPF] MVVM 간단하게 시작하기 - 3 (DB연동, DataGrid 활용)

재과장 2023. 1. 26.
반응형

정말 오랜만에 글을 쓰는 것 같습니다.

 

현생에 집중한다는 핑계로 멀리했었네요..

 

이제부터라도 꾸준히 제가 가지고 있는 C#에 대한 정보들을 써보려고 합니다.

한글로 되어 있는 WPF 관련 정보들이 많지 않아서 그런 것인지, 생각했던 것보다 많은 분들이 제 글을 찾아주시더라구요.

앞으로도 제가 가지고 있는 정보들이 많은 분들께 도움이 되었으면 좋겠습니다.


제가 MVVM 방식으로 프로그램을 만들어볼 때는 좋았던 점 중에 하나는 실시간으로 데이터가 바뀌어야할 때 View Model을 사용하면 편하게 연동할 수 있다는 점이었습니다.

 

예를 들어, 병원에 있는 환자대기 프로그램 같은 경우는 실시간으로 데이터가 갱신되기 때문에 View Model에 작성해서 View와의 Binding을 통해서 표시할 것 같습니다.(저라면..)

 

저도 이런 방법이 정확한 방법인지는 모르겠지만 저의 방법을 공유드리고자 글을 작성합니다.

(혹시 잘못된 방식이라면 댓글로 저와 많은분들과 지식을 공유했으면 좋겠습니다!)

 

 

 

그래서 오늘 같이 진행해볼 주제는 간단한

병원 대기자 모니터링 시스템

입니다.

이름은 거창하지만 아래의 기능만 사용해서 정말 정말! 간단히! 구현해보겠습니다.

  1. 간단한 DataGrid 작성
  2. View와 View Model의 연결
  3. 간단한 Timer 작성
  4. MS-SQL DB 연결

1. MVVM 틀 만들기

이번에 사용할 프로젝트 구성

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyMVVM.ViewModel
{
    class MainViewModel : INotifyPropertyChanged
    {

        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            { handler(this, new PropertyChangedEventArgs(name)); }
        }
    }
}

MainViewModel 기본

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;

namespace MyMVVM.View
{
    class Model : INotifyPropertyChanged
    {

        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            { handler(this, new PropertyChangedEventArgs(name)); }
        }
    }
}

Model 기본형

 

using System;
using System.Windows.Input;

namespace VehicleCallSystem.Core
{
    public class Command : ICommand
    {
        Action<object> _execute;
        Func<object, bool> _canExecute;

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }

        public Command(Action<object> execute, Func<object, bool> canExecute = null)
        {
            _execute = execute;
            _canExecute = canExecute;
        }

        public bool CanExecute(object parameter)
        {
            return _canExecute == null ? true : _canExecute(parameter);
        }

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

Command 기본형

 

위와 같이 작성하면 이제 시작할 준비가 되었습니다.

완성된 프로젝트는 공유해드릴 것이니 따라치시는 것을 추천하지만 바쁘시면 프로젝트 파일을 가져가셔도 좋습니다!

 


2. View 작성해보기

이전 글에서는 편의상 View를 구성할 때 Winform을 작성할 때와 마찬가지로 도구 상자를 사용했었습니다.

그런데 우리가 아는 이~쁜 WPF 프로그램을 작성하려면 XAML코드를 직접 작성하는 연습을 해야합니다.

사실 작성하는 것 정말 어색하고 싫었습니다만... 내가 원하는 그대로 명확히 표현하기 위해서는 XAML Code를 작성하지 않고는 불가능 하더군요.

 

그래서 앞으로는 같이 XAML Code도 작성해보면서 같이 연습해 나갔으면 합니다.

Grid Layout

<Window x:Class="MyMVVM.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">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="4*"/>
            <ColumnDefinition Width="1*"/>
        </Grid.ColumnDefinitions>

        <Grid.RowDefinitions>
            <RowDefinition Height="0.5*"/>
            <RowDefinition Height="2*"/>
        </Grid.RowDefinitions>
    </Grid>
</Window>

Column(Row)Definition 은 Grid 열(행)의 속성을 지정하는 부분인데, 이번에 사용한 속성외에도 정말 많은 속성이 있으니 필요하신 것이 있으면 하나씩 찾아가면서 적용해보는 것이 좋습니다.

(WPF 관련해서 친절한 자료가 많지 않아서 Top-Down 방식으로 공부하는 것을 추천드립니다.)

 

무튼!  위처럼 * 앞에 숫자를 표시하는 것은 비율이라고 생각하시면 되겠습니다. 원하는 길이가 있으시면 *표시를 제거하고 직접 길이를 쓰셔도 좋습니다.

 


사실 Grid에 내용을 하나씩 채워보는 과정을 거치려고 했는데, 이 글의 취지에서 벗어나는 느낌이 있어 View에 대한 다양한 활용법들은 다른 글로 작성할까 합니다.

Youtube에도 WPF 디자인에 관한 영상들이 많이 있으니 참고해주셔도 좋을 것 같습니다.

이번 글에서는 View는 중점이 아니니 제가 정말 간단하게 작성한 View와 DataGrid의 Binding 부분에 대해서만 설명하고 넘어가겠습니다. 

간단한 View 작성

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="4*"/>
            <ColumnDefinition Width="1*"/>
        </Grid.ColumnDefinitions>

        <Grid.RowDefinitions>
            <RowDefinition Height="0.5*"/>
            <RowDefinition Height="2*"/>
        </Grid.RowDefinitions>

        <Grid Grid.Row="0" Grid.Column="0">
            <Rectangle Width="420" Height="70" Fill="#FFFFEB3B"
                           RadiusX="2" RadiusY="2" VerticalAlignment="Center"/>
            <TextBlock Text="종합병원 대기시스템"
                           HorizontalAlignment="Center" VerticalAlignment="Center"
                           FontSize="32" Margin="0 00 0 15"/>
        </Grid>

        <!--Grid 2행 1열 설정-->
        <Grid Grid.Row="1" Grid.Column="0">
            <Border BorderBrush="LightGray" BorderThickness="2" Width="420">
                <StackPanel>
                    <!--DataGrid 설정-->
                    <DataGrid x:Name="DG1" Width="420" Height="255" ItemsSource="{Binding 데이터테이블}"
                                  AutoGenerateColumns="False" CanUserAddRows="False"
                                  HorizontalAlignment="Center"
                                  FontSize="20"
                                  Margin="-2,0">
                        <DataGrid.RowStyle>
                            <Style TargetType="DataGridRow">
                                <Setter Property="Height" Value="60"/>
                            </Style>
                        </DataGrid.RowStyle>


                        <DataGrid.Columns>

                            <!--호출번호 열 설정-->
                            <DataGridTextColumn Header="호출번호" Width="100"  FontSize="15" Binding="{Binding Path=호출번호}" IsReadOnly="True">
                                <DataGridTextColumn.ElementStyle>
                                    <Style TargetType="TextBlock">
                                        <Setter Property="HorizontalAlignment" Value="Center" />
                                        <Setter Property="VerticalAlignment" Value="Center"/>
                                    </Style>
                                </DataGridTextColumn.ElementStyle>
                            </DataGridTextColumn>

                            <!--진료실 열 설정-->
                            <DataGridTextColumn Header="진료실" Width="130"  FontSize="15" Binding="{Binding Path=진료실}" IsReadOnly="True" >
                                <DataGridTextColumn.ElementStyle>
                                    <Style TargetType="TextBlock">
                                        <Setter Property="HorizontalAlignment" Value="Center" />
                                        <Setter Property="VerticalAlignment" Value="Center"/>
                                    </Style>
                                </DataGridTextColumn.ElementStyle>
                            </DataGridTextColumn>

                            <!--성함 열 설정-->
                            <DataGridTextColumn Header="성함" Width="190"  FontSize="15" Binding="{Binding Path=성함}" IsReadOnly="True" >
                                <DataGridTextColumn.ElementStyle>
                                    <Style TargetType="TextBlock">
                                        <Setter Property="HorizontalAlignment" Value="Center" />
                                        <Setter Property="VerticalAlignment" Value="Center"/>
                                    </Style>
                                </DataGridTextColumn.ElementStyle>
                            </DataGridTextColumn>

                        </DataGrid.Columns>
                    </DataGrid>
                </StackPanel>
            </Border>
        </Grid>

        <!-- 열 설정-->
        <Grid Grid.RowSpan="1" Grid.Column="1">
            <Rectangle Height="323" Fill="Black"
                           RadiusX="2" RadiusY="2" VerticalAlignment="Bottom" Margin="0,0,0,-259"/>
        </Grid>
    </Grid>

매우 초보적인(...) 디자인으로 구성을 완료했습니다.

 

대부분의 코드는 그리드의 크기, 폰트 크기 등으로 디자인을 구성하는 요소들입니다.

 

WPF에서는 Winform과 다르게 DataGrid라는 것을 사용해서 데이터를 표시할 수 있는데, data를 Binding 하려면 아주 귀찮은 과정을 거치게 되더라구요.

 

먼저 DataGrid를 선언하고 각 열에 대한 설정을 각각 해줍니다.

 

귀찮기도 하고 반복작업이지만 이렇게 하면 열마다 내가 원하는 설정을 따로해줄 수 있습니다.

예를 들어, 어떤 열에만 MouseOver Event를 줘서 어떤 행동을 하게할 수도 있고 색을 바꿀 수 도 있고 많은 선택지가 있습니다.

지금은 따로 작성하지는 않았지만 앞으로 작성할 글에서 같이 확인해보면 좋을 것 같네요.

 

여기서 확인해야할 부분은 Datagrid 설정의 ItemSource, 열 설정의 Binding 부분입니다.

 

뒤에서 작성할 ViewModel과 Model에서 변수 이름을 적어줄 것이고, 현재는 작성하지 않았으니 한글로 표시해두었습니다.

이런 Binding 설정을 통해서 간단한게 View 와 ViewModel이 연결되는 것이죠.

 

분량조절에 실패해서 생각보다 글이 길어졌네요.

다음 글에서 작성하지 못한 ViewModel과 Model을 작성해보도록 하겠습니다.

 

여기까지 긴 글 읽어주셔서 감사합니다!

반응형

댓글