1장. WPF Binding 이용하여 프로젝트 실습

목적

  • WPF Binding 기술을 이용하여 주소록 관리 프로그램을 실습합니다.

요구사항

  • DataGrid 컨트롤 하나를 추가하여 주소록 관리 목록을 보여줍니다.
  • Button 컨트롤은 4개로, 추가, 삭제, 변경, 종료 4개의 버튼을 추가합니다.
  • 추가 버튼을 클릭하면, 회원을 추가하는 Sub 창이 출력됩니다.
  • 삭제 버튼을 클릭하면, 목록에서 선택된 데이터가 삭제됩니다.
  • 변경 버튼을 클릭하면, Sub 화면에 해당 열의 내용이 출력됩니다.
  • 종료 버튼을 누르면 프로그램이 종료됩니다.

실습

  • 요구사항 대로 프로젝트를 생성하여 실습합니다.

  • MainView.xaml

<Window x:Class="BindingTest.MainView"
        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:BindingTest"
        mc:Ignorable="d" 
        d:DataContext="{d:DesignInstance local:MainView}"
        Title="MainView" Height="328" Width="525"
        WindowStartupLocation="CenterScreen">
    <Grid>
        <DataGrid HorizontalAlignment="Left" 
                  Margin="10, 10, 0, 0" VerticalAlignment="Top"
                  Width="497"
                  SelectedIndex="{Binding Path=SelectedIndex,
                                          UpdateSourceTrigger=PropertyChanged,
                                          Mode=TwoWay}"
                  ItemsSource="{Binding Path=Persons, 
                                        UpdateSourceTrigger=PropertyChanged,
                                        Mode=OneWay}"
                  AutoGenerateColumns="False"
                  IsReadOnly="True">
            <DataGrid.Columns>
                <DataGridTextColumn Header="이름" Width="100"
                                    Binding="{Binding Path=Name}"/>
                <DataGridTextColumn Header="성별"
                                    Binding="{Binding Path=Gender}"/>
                <DataGridTextColumn Header="전화번호" Width="150"
                                    Binding="{Binding Path=PhoneNumber}"/>
                <DataGridTextColumn Header="주소" Width="*"
                                    Binding="{Binding Path=Address}"/>
            </DataGrid.Columns>
        </DataGrid>

        <Button Content="추가" 
                HorizontalAlignment="Left" Margin="192,249,0,0"
                VerticalAlignment="Top" Width="75"
                Command="{Binding AddCommand}"/>
        <Button Content="삭제" 
                HorizontalAlignment="Left" Margin="272, 249,0,0"
                VerticalAlignment="Top" Width="75"
                Command="{Binding DeleteCommand}"/>
        <Button Content="변경" 
                HorizontalAlignment="Left" Margin="352,249,0,0"
                VerticalAlignment="Top" Width="75"
                Command="{Binding ModifyCommand}"/>
        <Button Content="종료"
                HorizontalAlignment="Left" Margin="432,249,0,0"
                VerticalAlignment="Top" Width="75"
                Command="{Binding ExitCommand}"/>
    </Grid>
</Window>
  • MainView.xaml.cs
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;

namespace BindingTest
{
    /// <summary>
    /// MainView.xaml에 대한 상호 작용 논리
    /// </summary>
    public partial class MainView : Window, INotifyPropertyChanged
    {
        /// <summary>
        /// SelectedIndex Property
        /// </summary>
        private int _selectedIndex;
        public int SelectedIndex
        {
            get { return _selectedIndex; }
            set
            {
                _selectedIndex = value;
                OnPropertyChanged();
            }
        }

        public DelegateCommand AddCommand { get; set; }
        public DelegateCommand DeleteCommand { get; set; }
        public DelegateCommand ModifyCommand { get; set; }
        public DelegateCommand ExitCommand { get; set; }

        public ObservableCollection<Person> Persons { get; set; }

        public MainView()
        {
            InitializeComponent();

            this.DataContext = this;

            Persons = new ObservableCollection<Person>(); //ObservableCollection 객체 생성

            #region

            Persons.Add(new Person() { Address = "test1", Name = "홍길동1", Gender = true, PhoneNumber = "11111" });
            Persons.Add(new Person() { Address = "test2", Name = "홍길동2", Gender = true, PhoneNumber = "22222" });
            Persons.Add(new Person() { Address = "test3", Name = "홍길동3", Gender = true, PhoneNumber = "33333" });
            Persons.Add(new Person() { Address = "test4", Name = "홍길동4", Gender = false, PhoneNumber = "44444" });

            #endregion

            AddCommand = new DelegateCommand(_addCommandAction);
            DeleteCommand = new DelegateCommand(_deleteCommandAction);
            ModifyCommand = new DelegateCommand(_modifyCommandAction);
            ExitCommand = new DelegateCommand(_exitCommandAction);
        }

        private void _addCommandAction(object obj)
        {
            AddView add = new AddView();
            if(add.ShowDialog() == true)
            {
                Persons.Add(add.PersonData);
            }
        }

        private void _exitCommandAction(object obj)
        {
            this.Close();
        }

        private void _deleteCommandAction(object obj)
        {
            if(SelectedIndex < 0)
            {
                MessageBox.Show("선택된 데이터가 없습니다.", "주소록 v0.1", 
                    MessageBoxButton.OK, MessageBoxImage.Information);
                return;
            }

            Persons.RemoveAt(SelectedIndex); //선택된 Person 삭제
        }

        private void _modifyCommandAction(object obj)
        {
            if(SelectedIndex < 0)
            {
                MessageBox.Show("선택된 데이터가 없습니다.", "주소록 v0.1", 
                    MessageBoxButton.OK, MessageBoxImage.Information);
                return;
            }

            var selectData = Persons[SelectedIndex];
            var modifyData = new Person(selectData);

            AddView modify = new AddView(modifyData, AddView.ViewType.Modify);
            modify.PersonData = new Person(modifyData);

            if(modify.ShowDialog() == true)
            {
                Persons[SelectedIndex] = modify.PersonData;
            }
        }

        #region INotifyPropertyChanged

        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion
    }
}
  • AddView.xaml
<Window x:Class="BindingTest.AddView"
        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:BindingTest"
        mc:Ignorable="d"
        Title="{Binding Path=Caption, UpdateSourceTrigger=PropertyChanged}" Height="300" Width="300">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="2.5*"/>
        </Grid.ColumnDefinitions>

        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <Label Grid.Row="0" Grid.Column="0"
               Content="이름"
               HorizontalAlignment="Center"
               VerticalAlignment="Center"/>
        <TextBox Grid.Row="0" Grid.Column="1"
                 Width="200" Margin="4"
                 Text="{Binding Path=PersonData.Name,
                                UpdateSourceTrigger=PropertyChanged, 
                                Mode=TwoWay}"/>

        <Label Grid.Row="1" Grid.Column="0"
               Content="성별"
               HorizontalAlignment="Center"
               VerticalAlignment="Center"/>
        <TextBox Grid.Row="1" Grid.Column="1"
                 Width="200" Margin="4"
                 Text="{Binding Path=PersonData.Gender, 
                                UpdateSourceTrigger=PropertyChanged,
                                Mode=TwoWay}"/>

        <Label Grid.Row="2" Grid.Column="0"
               Content="전화번호" 
               HorizontalAlignment="Center"
               VerticalAlignment="Center"/>
        <TextBox Grid.Row="2" Grid.Column="1"
                   Width="200" Margin="4"
                   Text="{Binding Path=PersonData.PhoneNumber,
                                  UpdateSourceTrigger=PropertyChanged,
                                  Mode=TwoWay}"/>

        <Label Grid.Row="3" Grid.Column="0"
               Content="주소"
               VerticalAlignment="Center"
               HorizontalAlignment="Center"/>
        <TextBox Grid.Row="3" Grid.Column="1"
                 Width="200" Height="150" Margin="4"
                 Text="{Binding Path=PersonData.Address,
                                UpdateSourceTrigger=PropertyChanged,
                                Mode=TwoWay}"/>

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

            <Button Grid.Column="0" Margin="5"
                    Content="확인"
                    Command="{Binding OkCommand}"/>
            <Button Grid.Column="1" Margin="5"
                    Content="취소"
                    Command="{Binding CancelCommand}"/>
        </Grid>
    </Grid>
</Window>
  • AddView.xaml.cs
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;

namespace BindingTest
{
    /// <summary>
    /// AddView.xaml에 대한 상호 작용 논리
    /// </summary>
    public partial class AddView : Window, INotifyPropertyChanged
    {
        public enum ViewType
        {
            Add, Modify
        }

        private string _caption = "Title";
        public string Caption
        {
            get { return _caption; }
            set
            {
                _caption = value;
                OnPropertyChanged();
            }
        }

        public AddView(Person modifyData = null, ViewType type = ViewType.Add)
        {
            InitializeComponent();

            this.DataContext = this;

            if(type == ViewType.Add)
            {
                Caption = "추가";
                PersonData = new Person();
            }
            else if(type == ViewType.Modify)
            {
                Caption = "변경";
                PersonData = modifyData;
            }
            else
            {
                Caption = "추가";
                PersonData = new Person();
            }

            OkCommand = new DelegateCommand(_okCommandAction);
            CancelCommand = new DelegateCommand(_cancelCommandAction);
        }

        public Person PersonData { get; set; }

        public DelegateCommand OkCommand { get; set; }
        public DelegateCommand CancelCommand { get; set; }

        private void _cancelCommandAction(object obj)
        {
            DialogResult = false;
            this.Close();
        }

        private void _okCommandAction(object obj)
        {
            DialogResult = true;
            this.Close();
        }

        #region INotifyPropertyChanged

        public event PropertyChangedEventHandler PropertyChanged;

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

        #endregion
    }
}
  • DelegateCommand.cs
using System;
using System.Windows.Input;

namespace BindingTest
{
    public class DelegateCommand : ICommand
    {
        private readonly Predicate<object> _canExecute;
        private readonly Action<object> _execute;

        public event EventHandler CanExecuteChanged;

        public DelegateCommand(Action<object> execute) : this(execute, null) { }

        public DelegateCommand(Action<object> execute, Predicate<object> canExecute)
        {
            _execute = execute;
            _canExecute = canExecute;
        }

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

            return _canExecute(parameter); 
        }

        public void Execute(object parameter)
        {
            _execute(parameter);
        }
    }
}
  • Person.cs
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace BindingTest
{
    public class Person : INotifyPropertyChanged
    {
        #region INotifyPropertyChaged

        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion

        public Person() { }

        public Person(Person input) { }

        /// <summary>
        /// Name Property
        /// </summary>
        private string _name = string.Empty;
        public string Name
        {
            get { return _name; }
            set
            {
                _name = value;
                //CallerMemberName 이 자동으로 해당 Property 이름 찾아서 반환
                //값이 반환되면 Event 실행 = UI에 변화된 값 변경
                OnPropertyChanged(); 
            }
        }

        /// <summary>
        /// Gender Property
        /// </summary>
        private bool _gender = false;
        public bool Gender
        {
            get { return _gender; }
            set
            {
                _gender = value;
                OnPropertyChanged();
            }
        }

        /// <summary>
        /// PhoneNumber Property
        /// </summary>
        private string _phoneNumber = string.Empty;
        public string PhoneNumber
        {
            get { return _phoneNumber; }
            set
            {
                _phoneNumber = value;
                OnPropertyChanged();
            }
        }

        /// <summary>
        /// Address Property
        /// </summary>
        private string _address = string.Empty;
        public string Address
        {
            get { return _address; }
            set
            {
                _address = value;
                OnPropertyChanged();
            }
        }
    }
}
  • 실행결과

728x90

이 글을 공유하기

댓글

Designed by JB FACTORY