PersonalInfoApp

sz L·2023년 4월 24일
0

WPF

목록 보기
4/9
post-thumbnail

App.xaml

<Application x:Class="wp08_personalInfoApp.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:wp08_personalInfoApp"
             StartupUri="Views/MainView.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <!-- MahApps.Metro resource dictionaries. Make sure that all file names are Case Sensitive! -->
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
                <!-- Theme setting -->
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Themes/Light.Green.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

Views

MainView.xaml

<mah:MetroWindow 
    x:Class="wp08_personalInfoApp.Views.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:mah="http://metro.mahapps.com/winfx/xaml/controls"
    xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
    xmlns:local="clr-namespace:wp08_personalInfoApp.Views"
    mc:Ignorable="d"
    Title="Personal Info" Height="400" Width="700" ResizeMode="NoResize" WindowStartupLocation="CenterScreen" FontFamily="NanumGothic" >

    <mah:MetroWindow.IconTemplate>
        <DataTemplate>
            <iconPacks:PackIconMaterial Kind="AccountDetails" Width="24" Height="24" Margin="5,5,0,0" Foreground="White"/>
        </DataTemplate>
    </mah:MetroWindow.IconTemplate>

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

        <Grid Grid.Column="0" Margin="10,60">
            <Grid.RowDefinitions>
                <RowDefinition Height="1*"/>
                <RowDefinition Height="1*"/>
                <RowDefinition Height="1*"/>
                <RowDefinition Height="1*"/>
                <RowDefinition Height="1*"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="95"/>
                <ColumnDefinition Width="2*"/>
            </Grid.ColumnDefinitions>

            <Label Grid.Row="0" Grid.Column="0" Content="" FontSize="15" FontWeight="Bold"
                   HorizontalAlignment="Right" VerticalAlignment="Center" Margin="20,0"/>
            <Label Grid.Row="1" Grid.Column="0" Content="이름" FontSize="15" FontWeight="Bold"
                   HorizontalAlignment="Right" VerticalAlignment="Center" Margin="20,0"/>
            <Label Grid.Row="2" Grid.Column="0" Content="생일" FontSize="15" FontWeight="Bold"
                   HorizontalAlignment="Right" VerticalAlignment="Center" Margin="20,0"/>
            <Label Grid.Row="3" Grid.Column="0" Content="이메일" FontSize="15" FontWeight="Bold"
                   HorizontalAlignment="Right" VerticalAlignment="Center" Margin="20,0"/>
                
            <Button Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="2" Margin="100,10" Content="저장" 
                    Style="{StaticResource MahApps.Styles.Button.Square.Accent}"
                    Command="{Binding ProceedCommand}"/>

            <TextBox Grid.Row="0" Grid.Column="1" Margin="10,5" FontSize="15"
                     Text="{Binding InLastName}"
                     mah:TextBoxHelper.Watermark="성을 입력하세요"
                     mah:TextBoxHelper.UseFloatingWatermark="True"
                     mah:TextBoxHelper.ClearTextButton="True"/>
            <TextBox Grid.Row="1" Grid.Column="1" Margin="10,5" FontSize="15"
                     Text="{Binding InFirstName}"
                     mah:TextBoxHelper.Watermark="이름을 입력하세요"
                     mah:TextBoxHelper.UseFloatingWatermark="True"
                     mah:TextBoxHelper.ClearTextButton="True"/>
            <DatePicker Grid.Row="2" Grid.Column="1" Margin="10,5" FontSize="15"
                        SelectedDate="{Binding InDate , Mode=TwoWay}"
                        mah:TextBoxHelper.Watermark="생일을 선택하세요"
                        mah:TextBoxHelper.UseFloatingWatermark="True"
                        mah:TextBoxHelper.ClearTextButton="True"/>
            <TextBox Grid.Row="3" Grid.Column="1" Margin="10,5" FontSize="15"
                     Text="{Binding InEmail}"
                     mah:TextBoxHelper.Watermark="이메일을 입력하세요"
                     mah:TextBoxHelper.UseFloatingWatermark="True"
                     mah:TextBoxHelper.ClearTextButton="True"/>
        </Grid>

        <GroupBox Grid.Column="1" Margin="20" Header="결과">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="1*"/>
                    <RowDefinition Height="1*"/>
                    <RowDefinition Height="1*"/>
                    <RowDefinition Height="1*"/>
                    <RowDefinition Height="1*"/>
                    <RowDefinition Height="1*"/>
                    <RowDefinition Height="1*"/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="1*"/>
                    <ColumnDefinition Width="3*"/>
                </Grid.ColumnDefinitions>

                <!--<Label Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Content="결과" 
                   FontSize="20" FontWeight="ExtraBold" HorizontalAlignment="Center" Style="{StaticResource MahApps.Styles.Label}"/>-->

                <Label Grid.Row="1" Grid.Column="0" Content="" FontSize="12" FontWeight="Bold"
                   HorizontalAlignment="Right" VerticalAlignment="Center" Margin="10,5"/>
                <Label Grid.Row="2" Grid.Column="0" Content="이름" FontSize="12" FontWeight="Bold"
                   HorizontalAlignment="Right" VerticalAlignment="Center" Margin="10,5"/>
                <Label Grid.Row="3" Grid.Column="0" Content="이메일" FontSize="12" FontWeight="Bold"
                   HorizontalAlignment="Right" VerticalAlignment="Center" Margin="10,5"/>
                <Label Grid.Row="4" Grid.Column="0" Content="생일" FontSize="12" FontWeight="Bold"
                   HorizontalAlignment="Right" VerticalAlignment="Center" Margin="10,5"/>
                <Label Grid.Row="5" Grid.Column="0" Content="성년" FontSize="12" FontWeight="Bold"
                   HorizontalAlignment="Right" VerticalAlignment="Center" Margin="10,5"/>
                <Label Grid.Row="6" Grid.Column="0" Content="생일여부" FontSize="12" FontWeight="Bold"
                   HorizontalAlignment="Right" VerticalAlignment="Center" Margin="10,5"/>
                <Label Grid.Row="7" Grid.Column="0" Content="12지신" FontSize="12" FontWeight="Bold"
                   HorizontalAlignment="Right" VerticalAlignment="Center" Margin="10,5"/>

                <Label Grid.Row="1" Grid.Column="1" Content="{Binding OutLastName}"  FontSize="12" 
                   VerticalAlignment="Center" Margin="10,5"/>
                <Label Grid.Row="2" Grid.Column="1" Content="{Binding OutFirstName}" FontSize="12" 
                   VerticalAlignment="Center" Margin="10,5"/>
                <Label Grid.Row="3" Grid.Column="1" Content="{Binding OutDate}" FontSize="12" 
                   VerticalAlignment="Center" Margin="10,5"/>
                <Label Grid.Row="4" Grid.Column="1" Content="{Binding OutEmail}" FontSize="12" 
                   VerticalAlignment="Center" Margin="10,5"/>
                <Label Grid.Row="5" Grid.Column="1" Content="{Binding OutAdult}" FontSize="12" 
                   VerticalAlignment="Center" Margin="10,5"/>
                <Label Grid.Row="6" Grid.Column="1" Content="{Binding OutBirthDay}" FontSize="12" 
                   VerticalAlignment="Center" Margin="10,5"/>
                <Label Grid.Row="7" Grid.Column="1" Content="{Binding OutZodiac}" FontSize="12" 
                   VerticalAlignment="Center" Margin="10,5"/>
            </Grid>
        </GroupBox>

        
    </Grid>
</mah:MetroWindow>

MainView.xaml.cs

using MahApps.Metro.Controls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using wp08_personalInfoApp.ViewModels;  // 우리가 만든 뷰 모델 위치

namespace wp08_personalInfoApp.Views
{
    /// <summary>
    /// MainWindow.xaml에 대한 상호 작용 논리
    /// </summary>
    public partial class MainView : MetroWindow
    {
        public MainView()
        {
            InitializeComponent();
            this.DataContext = new MainViewModel(); 
            // 뷰모델 바인딩외 어떠한 이벤트핸들러 코드도 없음
        }
    }
}

ViewModels

MainViewModel.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using wp08_personalInfoApp.Models;

namespace wp08_personalInfoApp.ViewModels
{
    internal class MainViewModel :ViewModelBase
    {
        // View에서 사용할 멤버변수 선언
        private string inFirstName;
        private string inLastName;
        private string inEmail;
        private DateTime inDate = DateTime.Now;

        // 결과 출력쪽 변수
        private string outFirstName;
        private string outLastName;
        private string outEmail;
        private string outDate;     // 생일 출력할 땐 문자열로 대체
        private string outAdult;
        private string outBirthDay;
        private string outZodiac;

        // 실제로 사용할 속성
        #region <입력을 위한 속성>
        public string InFirstName
        {
            get => inFirstName;
            set
            {
                inFirstName = value;
                RaisePropertyChanged(nameof(InFirstName));  // "InFirstName"
            }
        }

        public string InLastName 
        { 
            get => inLastName; 
            set
            {
                inLastName = value;
                RaisePropertyChanged(nameof(inLastName)); 
            }
        }
        public string InEmail 
        { 
            get => inEmail; 
            set
            {
                inEmail = value;
                RaisePropertyChanged(nameof(InEmail));
            }
        }
        public DateTime InDate 
        { 
            get => inDate;
            set
            {
                inDate = value;
                RaisePropertyChanged(nameof(InDate));
            }
        }
        #endregion

        #region <출력을 위한 속성>
        public string OutFirstName 
        { 
            get => outFirstName;
            set
            {
                outFirstName = value;
                RaisePropertyChanged(nameof(OutFirstName));
            }
        }
        public string OutLastName 
        { 
            get => outLastName;
            set
            {
                outLastName = value;
                RaisePropertyChanged(nameof(OutLastName));
            }
        }
        public string OutEmail 
        { 
            get => outEmail;
            set
            {
                outEmail = value;
                RaisePropertyChanged(nameof(OutEmail));
            }
        }
        public string OutDate 
        { 
            get => outDate;
            set
            {
                outDate = value;
                RaisePropertyChanged(nameof(OutDate));
            }
        }
        public string OutAdult 
        { 
            get => outAdult;
            set
            {
                outAdult = value;
                RaisePropertyChanged(nameof(OutAdult));
            }
        }
        public string OutBirthDay 
        { 
            get => outBirthDay;
            set
            {
                outBirthDay = value;
                RaisePropertyChanged(nameof(OutBirthDay));
            }
        }
        public string OutZodiac 
        { 
            get => outZodiac;
            set
            {
                outZodiac = value;
                RaisePropertyChanged(nameof(OutZodiac));
            }
        }
        #endregion

        // 버튼 클릭에 대한 이벤트 처리(명령)
        private ICommand proceedCommand;
        public ICommand ProceedCommand
        {
            get
            {
                // 모든 입력에 값이 들어가야지 버튼이 활성화됨
                return proceedCommand ?? (proceedCommand = new RelayCommand<object>(
                    o => Proceed(), o => !string.IsNullOrEmpty(inFirstName) &&
                                         !string.IsNullOrEmpty(inLastName) &&
                                         !string.IsNullOrEmpty(inEmail) &&
                                         !string.IsNullOrEmpty(inDate.ToString())));
            }
        }

        // 버튼 클릭시 실제로 실행하는 메서드
        private void Proceed()
        {
            try
            {
                Person person = new Person(inFirstName, inLastName, inEmail, inDate);

                OutFirstName = person.FirstName;
                OutLastName = person.LastName;
                OutEmail = person.Email;
                OutDate = person.Date.ToString("yyyy년 MM월 dd일");
                OutAdult = person.IsAdult == true ? "성년" : "미성년";
                OutBirthDay = person.IsBrithDay == true ? "생일" : "-";
                OutZodiac = person.Zodiac;
            }
            catch (Exception ex)
            {
                MessageBox.Show($"예외발생 {ex.Message}");
            }
        }
    }
}

RelayCommand.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace wp08_personalInfoApp
{

    /// <summary>
    /// ViewModel과 View를 Glue하기 위한 클래스
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class RelayCommand<T> : ICommand
    {
        private readonly Action<T> execute;  // 실행처리를 위한 Generic
        private readonly Predicate<T> canExecute; // 실행여부를 판단하는 Generic

        // 실행여부에 따라서 이벤틀 추가해주거나 삭제하는 이벤트핸들러
        public event EventHandler CanExecuteChanged
        {
            add
            {
                CommandManager.RequerySuggested += value;
            }
            remove
            {
                CommandManager.RequerySuggested -= value;
            }
        }

        // 실행할 수 없으면 false 리턴 반대면 true
        public bool CanExecute(object parameter)
        {
            return canExecute?.Invoke((T)parameter) ?? true;
        }

        // 실행
        public void Execute(object parameter)
        {
            execute((T)parameter);
        }

        /// <summary>
        /// execute만 파라미터 받는 생성자
        /// </summary>
        /// <param name="execute"></param>
        public RelayCommand(Action<T> execute) : this(execute, null) { }

        /// <summary>
        /// execute, canExecute를 파라미터로 받는 생성자
        /// </summary>
        /// <param name="execute"></param>
        /// <param name="canExecute"></param>
        /// <exception cref="ArgumentNullException"></exception>
        public RelayCommand(Action<T> execute, Predicate<T> canExecute = null)
        {
            this.execute = execute ?? throw new ArgumentNullException(nameof(execute));
            this.canExecute = canExecute;
        }
    }
}

ViewModelBase.cs

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

namespace wp08_personalInfoApp.ViewModels
{
    // 프로퍼티가 변동되면 시스템에 알려주는 역할
    internal class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public void RaisePropertyChanged(string propertyName)
        {
            if(PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

Models

Person.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using wp08_personalInfoApp.Logics;

namespace wp08_personalInfoApp.Models
{
    internal class Person
    {
        // 외부에서 접근불가
        private string email;
        private DateTime date;

        public string FirstName { get; set; } // Auto Property
        public string LastName { get; set; } // Auto Property 
        public string Email 
        { 
            get => email; 
            set
            {
                if(Commons.IsValidEmail(value) != true) // 이메일이 형식에 맞지 않으면
                {
                    throw new Exception("유효하지 않은 이메일형식");
                }
                else
                {
                    email = value;
                }
            }
        }
        public DateTime Date 
        { 
            get => date; 
            set
            {
                var result = Commons.GetAge(value);
                if (result > 120 || result <= 0)
                {
                    throw new Exception("유효하지 않은 생일");
                }
                else
                {
                    date = value;
                }
            }
        }

        public bool IsAdult
        {
            get => Commons.GetAge(date) > 18;   // 19살 이상이면 true
        }

        public bool IsBrithDay
        {
            get
            {
                return DateTime.Now.Month == date.Month &&
                    DateTime.Now.Day == date.Day;   //오늘하고 월 일 같으면 생일
            }
        }

        public string Zodiac
        {
            get => Commons.GetZodiac(date);     // 12지로 띠를 받아옴
        }

        public Person(string firstName, string lastName, string email, DateTime date)
        {
            FirstName = firstName;
            LastName = lastName;
            Email = email;
            Date = date;
        }
    }
}

Logics

Commons.cs

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

namespace wp08_personalInfoApp.Logics
{
    internal class Commons
    {
            // Reqular Expression 정규표형식
            //이메일 형식에 맞게 입력하도록 체크(검증체크)
        public static bool IsValidEmail(string email)
        {
            var strPattern = @"^([0-9a-zA-Z]+)@([0-9a-zA-Z]+)(\.[0-9a-zA-Z]+){1,}$"; // 정규표현식
            return Regex.IsMatch(email, strPattern);
        }
        public static int GetAge(DateTime value)
        {
            // 입력된 날짜로 나이 계산
            int result;
            if(DateTime.Now.Month < value.Month || DateTime.Now.Month == value.Month &&
                DateTime.Now.Day < value.Day)
            {
                result = DateTime.Now.Year - value.Year - 1; //아직 생일 안지남
            }
            else
            {
                result = DateTime.Now.Year - value.Year;
            }
            return result;
        }
        public static string GetZodiac(DateTime value)
        {
            // 입력된 생일로 12지신을 리턴
            int reminder = value.Year % 12;
            switch(reminder)
            {
                case 4:
                    return "쥐띠";
                case 5:
                    return "소띠";
                case 6:
                    return "호랑이띠";
                case 7:
                    return "토끼띠";
                case 8:
                    return "용띠";
                case 9:
                    return "뱀띠";
                case 10:
                    return "말띠";
                case 11:
                    return "양띠";
                case 0:
                    return "원숭이띠";
                case 1:
                    return "닭띠";
                case 2:
                    return "개띠";
                case 3:
                    return "돼지띠";
                default:
                    return "잡띠";
            }
        }
    }
}

실행결과

profile
가랑비는 맞는다 하지만 폭풍은 내 것이야

0개의 댓글