■ 날짜 선택기 사용하기

----------------------------------------------------------------------------------------------------


TestProject.zip


DatePicker.xaml

 

 

<UserControl x:Class="TestProject.DatePicker"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:g="clr-namespace:System.Globalization;assembly=mscorlib">

    <UserControl.Resources>

        <Style TargetType="{x:Type RepeatButton}">

            <Setter Property="Width"     Value="{Binding RelativeSource={RelativeSource self}, Path=ActualHeight}" />

            <Setter Property="Focusable" Value="False"                                                             />

            <Style.Triggers>

                <DataTrigger Binding="{Binding ElementName=notApplicableCheckBox, Path=IsChecked}" Value="True">

                    <Setter Property="IsEnabled" Value="False" />

                </DataTrigger>

            </Style.Triggers>

        </Style>

        <Style

            TargetType="{x:Type StatusBarItem}">

            <Setter Property="Margin"              Value="1"      />

            <Setter Property="HorizontalAlignment" Value="Center" />

            <Setter Property="VerticalAlignment"   Value="Center" />

        </Style>

        <Style TargetType="{x:Type ListBoxItem}">

            <Setter Property="BorderThickness"            Value="1"           />

            <Setter Property="BorderBrush"                Value="Transparent" />

            <Setter Property="Margin"                     Value="1"           />

            <Setter Property="HorizontalContentAlignment" Value="Center"      />

            <Style.Triggers>

                <MultiTrigger>

                    <MultiTrigger.Conditions>

                        <Condition Property="IsSelected"                 Value="True" />

                        <Condition Property="Selector.IsSelectionActive" Value="False" />

                    </MultiTrigger.Conditions>

                    <Setter Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" />

                </MultiTrigger>

                <DataTrigger Binding="{Binding ElementName=notApplicableCheckBox, Path=IsChecked}" Value="True">

                    <Setter Property="IsEnabled" Value="False" />

                </DataTrigger>

            </Style.Triggers>

        </Style>

    </UserControl.Resources>

    <Border

        BorderThickness="1"

        BorderBrush="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}">

        <Grid>

            <Grid.RowDefinitions>

                <RowDefinition Height="Auto" />

                <RowDefinition Height="Auto" />

                <RowDefinition Height="Auto" />

                <RowDefinition Height="Auto" />

            </Grid.RowDefinitions>

            <Grid

                Background="{DynamicResource {x:Static SystemColors.ControlDarkDarkBrushKey}}"

                TextBlock.Foreground="{DynamicResource {x:Static SystemColors.ControlLightLightBrushKey}}">

                <Grid.ColumnDefinitions>

                    <ColumnDefinition Width="Auto" />

                    <ColumnDefinition Width="*"    />

                    <ColumnDefinition Width="Auto" />

                </Grid.ColumnDefinitions>

                <RepeatButton Grid.Column="0"

                    FontWeight="Bold"

                    Content="◀"

                    Click="previousButon_Click" />

                <TextBlock Name="monthYearTextBlock" Grid.Column="1"

                    HorizontalAlignment="Center"

                    VerticalAlignment="Center"

                    Margin="3" />

                <RepeatButton Grid.Column="2"

                    FontWeight="Bold"

                    Content="▶"

                    Click="nextButton_Click" />

            </Grid>

            <StatusBar Grid.Row="1"

                ItemsSource="{Binding Source={x:Static g:DateTimeFormatInfo.CurrentInfo}, Path=AbbreviatedDayNames}">

                <StatusBar.ItemsPanel>

                    <ItemsPanelTemplate>

                        <UniformGrid Rows="1" />

                    </ItemsPanelTemplate>

                </StatusBar.ItemsPanel>

            </StatusBar>

            <Border Grid.Row="2"

                BorderThickness="0 1 0 1"

                BorderBrush="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}">

                <ListBox Name="monthListBox"

                    SelectionChanged="monthListBox_SelectionChanged">

                    <ListBox.ItemsPanel>

                        <ItemsPanelTemplate>

                            <UniformGrid Name="monthUniformGrid"

                                Background="{DynamicResource {x:Static SystemColors.ControlLightBrushKey}}"

                                Columns="7"

                                Rows="6"

                                IsItemsHost="True" />

                        </ItemsPanelTemplate>

                    </ListBox.ItemsPanel>

                    <ListBoxItem>dummy item</ListBoxItem>

                </ListBox>

            </Border>

            <CheckBox Name="notApplicableCheckBox" Grid.Row="3"

                Margin="3"

                HorizontalAlignment="Center"

                VerticalAlignment="Center"

                Checked="notApplicableCheckBox_Checked"

                Unchecked="notApplicableCheckBox_Unchecked">

                Not applicable

            </CheckBox>

        </Grid>

    </Border>

</UserControl>

 

 

DatePicker.cs

 

 

using System;

using System.Globalization;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Controls.Primitives;

using System.Windows.Input;

using System.Windows.Media;

 

namespace TestProject

{

    /// <summary>

    /// 일자 선택기

    /// </summary>

    public partial class DatePicker

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field

        ////////////////////////////////////////////////////////////////////////////////////////// Static

        //////////////////////////////////////////////////////////////////////////////// Public

 

        #region Field

 

        /// <summary>

        /// 일자 속성

        /// </summary>

        public static readonly DependencyProperty DateProperty = DependencyProperty.Register

        (

            "Date",

            typeof(DateTime?),

            typeof(DatePicker),

            new PropertyMetadata

            (

                new DateTime(),

                DatePropertyChanged

            )

        );

 

        /// <summary>

        /// 일자 변경시 이벤트

        /// </summary>

        public static readonly RoutedEvent DateChangedEvent = EventManager.RegisterRoutedEvent

        (

            "DateChanged",

            RoutingStrategy.Bubble,

            typeof(RoutedPropertyChangedEventHandler<DateTime?>),

            typeof(DatePicker)

        );

 

        #endregion

 

        ////////////////////////////////////////////////////////////////////////////////////////// Instance

        //////////////////////////////////////////////////////////////////////////////// Private

 

        #region Field

 

        /// <summary>

        /// 월 UniformGrid

        /// </summary>

        private UniformGrid monthUniformGrid;

 

        /// <summary>

        /// 저장 일시

        /// </summary>

        private DateTime saveDateTime = DateTime.Now.Date;

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 일자 - Date

 

        /// <summary>

        /// 일자

        /// </summary>

        public DateTime? Date

        {

            set

            {

                SetValue(DateProperty, value);

            }

            get

            {

                return (DateTime?)GetValue(DateProperty);

            }

        }

 

        #endregion

        #region 일자 변경시 이벤트 - RoutedPropertyChangedEventHandler<DateTime?> DateChanged

 

        /// <summary>

        /// 일자 변경시 이벤트

        /// </summary>

        public event RoutedPropertyChangedEventHandler<DateTime?> DateChanged

        {

            add

            {

                AddHandler(DateChangedEvent, value);

            }

            remove

            {

                RemoveHandler(DateChangedEvent, value);

            }

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 생성자 - DatePicker()

 

        /// <summary>

        /// 생성자

        /// </summary>

        public DatePicker()

        {

            InitializeComponent();

 

            Date = this.saveDateTime;

 

            Loaded += UserControl_Loaded;

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

        ////////////////////////////////////////////////////////////////////////////////////////// Static

        //////////////////////////////////////////////////////////////////////////////// Private

 

        #region 일자 속성 변경시 처리하기 - DatePropertyChanged(dependencyObject, e)

 

        /// <summary>

        /// 일자 속성 변경시 처리하기

        /// </summary>

        /// <param name="dependencyObject">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private static void DatePropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)

        {

            (dependencyObject as DatePicker).OnDateChanged((DateTime?)e.OldValue, (DateTime?)e.NewValue);

        }

 

        #endregion

 

        ////////////////////////////////////////////////////////////////////////////////////////// Instance

        //////////////////////////////////////////////////////////////////////////////// Protected

 

        #region 프리뷰 키 다운시 처리하기 - OnPreviewKeyDown(e)

 

        /// <summary>

        /// 프리뷰 키 다운시 처리하기

        /// </summary>

        /// <param name="e">이벤트 인자</param>

        protected override void OnPreviewKeyDown(KeyEventArgs e)

        {

            base.OnKeyDown(e);

 

            if(e.Key == Key.PageDown)

            {

                FlipPage(true);

 

                e.Handled = true;

            }

            else if(e.Key == Key.PageUp)

            {

                FlipPage(false);

 

                e.Handled = false;

            }

        }

 

        #endregion

        #region 일자 변경시 처리하기 - OnDateChanged(before, after)

 

        /// <summary>

        /// 일자 변경시 처리하기

        /// </summary>

        /// <param name="before">변경전 일시</param>

        /// <param name="after">변경후 일시</param>

        protected virtual void OnDateChanged(DateTime? before, DateTime? after)

        {

            this.notApplicableCheckBox.IsChecked = after == null;

 

            if(after != null)

            {

                DateTime afterValue = (DateTime)after;

 

                this.monthYearTextBlock.Text = afterValue.ToString(DateTimeFormatInfo.CurrentInfo.YearMonthPattern);

 

                if(this.monthUniformGrid != null)

                {

                    this.monthUniformGrid.FirstColumn = (int)(new DateTime(afterValue.Year, afterValue.Month, 1).DayOfWeek);

                }

 

                int dayCountInMonth = DateTime.DaysInMonth(afterValue.Year, afterValue.Month);

 

                if(dayCountInMonth != this.monthListBox.Items.Count)

                {

                    this.monthListBox.BeginInit();

 

                    this.monthListBox.Items.Clear();

 

                    for(int i = 0; i < dayCountInMonth;  i++)

                    {

                        this.monthListBox.Items.Add((i + 1).ToString());

                    }

 

                    this.monthListBox.EndInit();

                }

 

                this.monthListBox.SelectedIndex = afterValue.Day - 1;

            }

 

            RoutedPropertyChangedEventArgs<DateTime?> e = new RoutedPropertyChangedEventArgs<DateTime?>

            (

                before,

                after,

                DatePicker.DateChangedEvent

            );

 

            e.Source = this;

 

            RaiseEvent(e);

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////// Private

        ////////////////////////////////////////////////////////////////////// Event

 

        #region 사용자 컨트롤 로드시 처리하기 - UserControl_Loaded(sender, e)

 

        /// <summary>

        /// 사용자 컨트롤 로드시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void UserControl_Loaded(object sender, RoutedEventArgs e)

        {

            this.monthUniformGrid = GetUniformGrid(this.monthListBox);

 

            if(Date != null)

            {

                DateTime dateValue = (DateTime)Date;

 

                this.monthUniformGrid.FirstColumn = (int)(new DateTime(dateValue.Year, dateValue.Month, 1).DayOfWeek);

            }

        }

 

        #endregion

        #region 이전 버튼 클릭시 처리하기 - previousButon_Click(sender, e)

 

        /// <summary>

        /// 이전 버튼 클릭시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void previousButon_Click(object sender, RoutedEventArgs e)

        {

            FlipPage(true);

        }

 

        #endregion

        #region 다음 버튼 클릭시 처리하기 - nextButton_Click(sender, e)

 

        /// <summary>

        /// 다음 버튼 클릭시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void nextButton_Click(object sender, RoutedEventArgs e)

        {

            FlipPage(false);

        }

 

        #endregion

        #region 월 리스트 박스 선택 변경시 처리하기 - monthListBox_SelectionChanged(sender, e)

 

        /// <summary>

        /// 월 리스트 박스 선택 변경시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void monthListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)

        {

            if(Date == null)

            {

                return;

            }

 

            DateTime dateValue = (DateTime)Date;

 

            if(this.monthListBox.SelectedIndex != -1)

            {

                Date = new DateTime(dateValue.Year, dateValue.Month, Int32.Parse(this.monthListBox.SelectedItem as string));

            }

        }

 

        #endregion

        #region Not Applicable 체크 박스 체크시 처리하기 - notApplicableCheckBox_Checked(sender, e)

 

        /// <summary>

        /// Not Applicable 체크 박스 체크시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void notApplicableCheckBox_Checked(object sender, RoutedEventArgs e)

        {

            if(Date != null)

            {

                this.saveDateTime = (DateTime)Date;

 

                Date = null;

            }

        }

 

        #endregion

        #region Not Applicable 체크 박스 체크 해제시 처리하기 - notApplicableCheckBox_Unchecked(sender, e)

 

        /// <summary>

        /// Not Applicable 체크 박스 체크 해제시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void notApplicableCheckBox_Unchecked(object sender, RoutedEventArgs e)

        {

            Date = this.saveDateTime;

        }

 

        #endregion

 

        ////////////////////////////////////////////////////////////////////// Function

 

        #region UniformGrid 객체 - GetUniformGrid(dependencyObject)

 

        /// <summary>

        /// UniformGrid 객체 구하기

        /// </summary>

        /// <param name="dependencyObject">DependencyObject</param>

        /// <returns>UniformGrid 객체</returns>

        private UniformGrid GetUniformGrid(DependencyObject dependencyObject)

        {

            if(dependencyObject is UniformGrid)

            {

                return dependencyObject as UniformGrid;

            }

 

            for(int i = 0; i < VisualTreeHelper.GetChildrenCount(dependencyObject); i++)

            {

                Visual visual = GetUniformGrid(VisualTreeHelper.GetChild(dependencyObject, i));

 

                if(visual != null)

                {

                    return visual as UniformGrid;

                }

            }

 

            return null;

        }

 

        #endregion

        #region 페이지 플립하기 - FlipPage(isPrevious)

 

        /// <summary>

        /// 페이지 플립하기

        /// </summary>

        /// <param name="isPrevious">이전 여부</param>

        private void FlipPage(bool isPrevious)

        {

            if(Date == null)

            {

                return;

            }

 

            DateTime dateValue = (DateTime)Date;

 

            int pageNumber = isPrevious ? -1 : 1;

 

            if(Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))

            {

                pageNumber *= 12;

            }

 

            if(Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))

            {

                pageNumber = Math.Max(-1200, Math.Min(1200, 120 * pageNumber));

            }

 

            int year  = dateValue.Year  + pageNumber / 12;

            int month = dateValue.Month + pageNumber % 12;

 

            while(month < 1)

            {

                month += 12;

                year  -= 1;

            }

 

            while(month > 12)

            {

                month -= 12;

                year  += 1;

            }

 

            if(year < DateTime.MinValue.Year)

            {

                Date = DateTime.MinValue.Date;

            }

            else if(year > DateTime.MaxValue.Year)

            {

                Date = DateTime.MaxValue.Date;

            }

            else

            {

                Date = new DateTime(year, month, Math.Min(dateValue.Day, DateTime.DaysInMonth(year, month)));

            }

        }

 

        #endregion

    }

}

 

 

MainWindow.xaml

 

 

<Window x:Class="TestProject.MainWindow"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:src="clr-namespace:TestProject"

    ResizeMode="CanMinimize"

    SizeToContent="WidthAndHeight"

    Title="날짜 선택기 사용하기"

    FontFamily="나눔고딕코딩"

    FontSize="16">

    <StackPanel>

        <src:DatePicker x:Name="datePicker"

            Margin="12"

            HorizontalAlignment="Center"

            DateChanged="datePicker_DateChanged" />

        <StackPanel

            Margin="12"

            Orientation="Horizontal">

            <TextBlock Text="Bound value : " />

            <TextBlock Text="{Binding ElementName=datePicker, Path=Date}" />

        </StackPanel>

        <StackPanel

            Margin="12"

            Orientation="Horizontal">

            <TextBlock Text="Event handler value : " />

            <TextBlock Name="dateTextBlock" />

        </StackPanel>

    </StackPanel>

</Window>

 

 

MainWindow.cs

 

 

using System;

using System.Windows;

 

namespace TestProject

{

    /// <summary>

    /// 메인 윈도우

    /// </summary>

    public partial class MainWindow : Window

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 생성자 - MainWindow()

 

        /// <summary>

        /// 생성자

        /// </summary>

        public MainWindow()

        {

            InitializeComponent();

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

        ////////////////////////////////////////////////////////////////////////////////////////// Private

 

        #region 일자 선택기 일자 변경시 처리하기 - datePicker_DateChanged(sender, e)

 

        /// <summary>

        /// 일자 선택기 일자 변경시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void datePicker_DateChanged(object sender, RoutedPropertyChangedEventArgs<DateTime?> e)

        {

            if(e.NewValue != null)

            {

                DateTime dateTime = (DateTime)e.NewValue;

 

                this.dateTextBlock.Text = dateTime.ToString("d");

            }

            else

            {

                this.dateTextBlock.Text = string.Empty;

            }

        }

 

        #endregion

    }

}

 

----------------------------------------------------------------------------------------------------

Posted by 사용자 icodebroker
TAG

댓글을 달아 주세요