첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
본 블로그는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 블로그 콘텐츠 향상을 위해 쓰여집니다.

728x90
반응형

TestProject.zip
0.02MB

▶ CommandManager.cs

using System;
using System.Collections.Generic;

namespace TestProject
{
    /// <summary>
    /// 명령 관리자
    /// </summary>
    public class CommandManager
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Public

        #region 약한 참조 핸들러 추가하기 - AddWeakReferenceHandler(weakReferenceList, eventHandler)

        /// <summary>
        /// 약한 참조 핸들러 추가하기
        /// </summary>
        /// <param name="weakReferenceList">약한 참조 리스트</param>
        /// <param name="eventHandler">이벤트 핸들러</param>
        public static void AddWeakReferenceHandler(ref List<WeakReference> weakReferenceList, EventHandler eventHandler)
        {
            if(weakReferenceList == null)
            {
                weakReferenceList = new List<WeakReference>();
            }

            weakReferenceList.Add(new WeakReference(eventHandler));
        }

        #endregion
        #region 약한 참조 핸들러 제거하기 - RemoveWeakReferenceHandler(weakReferenceList, eventHandler)

        /// <summary>
        /// 약한 참조 핸들러 제거하기
        /// </summary>
        /// <param name="weakReferenceList">약한 참조 리스트</param>
        /// <param name="eventHandler">이벤트 핸들러</param>
        public static void RemoveWeakReferenceHandler(List<WeakReference> weakReferenceList, EventHandler eventHandler)
        {
            if(weakReferenceList != null)
            {
                for(int i = weakReferenceList.Count - 1; i >= 0; i--)
                {
                    WeakReference weakReference = weakReferenceList[i];

                    EventHandler existingEventHandler = weakReference.Target as EventHandler;
                   
                    if((existingEventHandler == null) || (existingEventHandler == eventHandler))
                    {
                        weakReferenceList.RemoveAt(i);
                    }
                }
            }
        }

        #endregion
        #region 약한 참조 핸들러 호출하기 - CallWeakReferenceHandlers(weakReferenceList)

        /// <summary>
        /// 약한 참조 핸들러 호출하기
        /// </summary>
        /// <param name="weakReferenceList">약한 참조 리스트</param>
        public static void CallWeakReferenceHandlers(List<WeakReference> weakReferenceList)
        {
            if(weakReferenceList != null)
            {
                EventHandler[] eventHandlerArray = new EventHandler[weakReferenceList.Count];

                int count = 0;

                for(int i = weakReferenceList.Count - 1; i >= 0; i--)
                {
                    WeakReference weakReference = weakReferenceList[i];

                    EventHandler eventHandler = weakReference.Target as EventHandler;
                    
                    if(eventHandler == null)
                    {
                        weakReferenceList.RemoveAt(i);
                    }
                    else
                    {
                        eventHandlerArray[count] = eventHandler;

                        count++;
                    }
                }

                for(int i = 0; i < count; i++)
                {
                    EventHandler eventHandler = eventHandlerArray[i];

                    eventHandler(null, EventArgs.Empty);
                }
            }
        }

        #endregion
    }
}

 

728x90

 

▶ DelegateCommand.cs

using System;
using System.Collections.Generic;
using System.Windows.Input;

namespace TestProject
{
    /// <summary>
    /// 대리자 명령
    /// </summary>
    public class DelegateCommand : ICommand
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Event
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 실행 가능 여부 변경시 이벤트 - CanExecuteChanged

        /// <summary>
        /// 실행 가능 여부 변경시 이벤트
        /// </summary>
        public event EventHandler CanExecuteChanged
        {
            add
            {
                CommandManager.AddWeakReferenceHandler(ref this.weakReferenceList, value);
            }
            remove
            {
                CommandManager.RemoveWeakReferenceHandler(this.weakReferenceList, value);
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 실행 액션
        /// </summary>
        private readonly Action executeAction;

        /// <summary>
        /// 실행 가능 여부 함수
        /// </summary>
        private readonly Func<bool> canExecuteFunction;

        /// <summary>
        /// 약한 참조 리스트
        /// </summary>
        private List<WeakReference> weakReferenceList;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - DelegateCommand(executeAction, canExecuteFunction)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="executeAction">실행 액션</param>
        /// <param name="canExecuteFunction">실행 가능 여부 함수</param>
        public DelegateCommand(Action executeAction, Func<bool> canExecuteFunction)
        {
            if(executeAction == null)
            {
                throw new ArgumentNullException("executeAction");
            }

            this.executeAction      = executeAction;
            this.canExecuteFunction = canExecuteFunction;
        }

        #endregion
        #region 생성자 - DelegateCommand(executeAction)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="executeAction">실행 액션</param>
        public DelegateCommand(Action executeAction) : this(executeAction, null)
        {
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 실행 가능 여부 구하기 - CanExecute()

        /// <summary>
        /// 실행 가능 여부 구하기
        /// </summary>
        /// <returns>실행 가능 여부</returns>
        public bool CanExecute()
        {
            if(this.canExecuteFunction != null)
            {
                return this.canExecuteFunction();
            }

            return true;
        }

        #endregion
        #region 실행 가능 여부 구하기 - ICommand.CanExecute(parameter)

        /// <summary>
        /// 실행 가능 여부 구하기
        /// </summary>
        /// <param name="parameter">매개 변수</param>
        /// <returns>실행 가능 여부</returns>
        bool ICommand.CanExecute(object parameter)
        {
            return CanExecute();
        }

        #endregion
        #region 실행하기 - Execute()

        /// <summary>
        /// 실행하기
        /// </summary>
        public void Execute()
        {
            if(this.executeAction != null)
            {
                this.executeAction();
            }
        }

        #endregion
        #region 실행하기 - ICommand.Execute(parameter)

        /// <summary>
        /// 실행하기
        /// </summary>
        /// <param name="parameter">매개 변수</param>
        void ICommand.Execute(object parameter)
        {
            Execute();
        }

        #endregion

        #region 실행 가능 여부 변경시 이벤트 발생시키기 - RaiseCanExecuteChangedEvent()

        /// <summary>
        /// 실행 가능 여부 변경시 이벤트 발생시키기
        /// </summary>
        public void RaiseCanExecuteChangedEvent()
        {
            FireCanExecuteChangedEvent();
        }

        #endregion

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

        #region 실행 가능 여부 변경시 이벤트 발생시키기 - FireCanExecuteChangedEvent()

        /// <summary>
        /// 실행 가능 여부 변경시 이벤트 발생시키기
        /// </summary>
        protected virtual void FireCanExecuteChangedEvent()
        {
            CommandManager.CallWeakReferenceHandlers(this.weakReferenceList);
        }

        #endregion
    }
}

 

300x250

 

▶ CircularProgressBar.xaml

<UserControl x:Class="TestProject.CircularProgressBar"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="45"
    Height="45"
    Background="Transparent">
    <UserControl.Resources>
        <SolidColorBrush x:Key="EllipseSolidColorBrushKey"
            Color="#ff2e6187" />
    </UserControl.Resources>
    <Viewbox
        HorizontalAlignment="Center"
        VerticalAlignment="Center"
        Width="40"
        Height="40">
        <Grid
            VerticalAlignment="Center"
            HorizontalAlignment="Center"
            Background="Transparent">
            <Canvas Name="canvas"
                HorizontalAlignment="Center"
                VerticalAlignment="Center"
                Width="120"
                Height="120"
                RenderTransformOrigin="0.5 0.5">
                <Ellipse Name="ellipse0" Canvas.Left="0" Canvas.Top="0"
                     Width="20"
                     Height="20"
                     Stretch="Fill"
                     Opacity="1.0"
                     Fill="{StaticResource EllipseSolidColorBrushKey}" />
                <Ellipse Name="ellipse1" Canvas.Left="0" Canvas.Top="0"
                    Width="20"
                    Height="20"
                    Stretch="Fill"
                    Opacity="0.9"
                    Fill="{StaticResource EllipseSolidColorBrushKey}" />
                <Ellipse Name="ellipse2" Canvas.Left="0" Canvas.Top="0"
                     Width="20"
                     Height="20"
                     Stretch="Fill"
                     Opacity="0.8"
                     Fill="{StaticResource EllipseSolidColorBrushKey}" />
                <Ellipse Name="ellipse3" Canvas.Left="0" Canvas.Top="0"
                     Width="20"
                     Height="20"
                     Stretch="Fill"
                     Opacity="0.7"
                     Fill="{StaticResource EllipseSolidColorBrushKey}" />
                <Ellipse Name="ellipse4" Canvas.Left="0" Canvas.Top="0"
                     Width="20"
                     Height="20"
                     Stretch="Fill"
                     Opacity="0.6"
                     Fill="{StaticResource EllipseSolidColorBrushKey}" />
                <Ellipse Name="ellipse5" Canvas.Left="0" Canvas.Top="0"
                     Width="20"
                     Height="20"
                     Stretch="Fill"
                     Opacity="0.5"
                     Fill="{StaticResource EllipseSolidColorBrushKey}" />
                <Ellipse Name="ellipse6" Canvas.Left="0" Canvas.Top="0"
                     Width="20"
                     Height="20"
                     Stretch="Fill"
                     Opacity="0.4"
                     Fill="{StaticResource EllipseSolidColorBrushKey}" />
                <Ellipse Name="ellipse7" Canvas.Left="0" Canvas.Top="0"
                     Width="20"
                     Height="20"
                     Stretch="Fill"
                     Opacity="0.3"
                     Fill="{StaticResource EllipseSolidColorBrushKey}" />
                <Ellipse Name="ellipse8" Canvas.Left="0" Canvas.Top="0"
                     Width="20"
                     Height="20"
                     Stretch="Fill"
                     Opacity="0.2"
                     Fill="{StaticResource EllipseSolidColorBrushKey}" />
                <Canvas.RenderTransform>
                    <RotateTransform x:Name="rotateTransform"
                        Angle="0" />
                </Canvas.RenderTransform>
            </Canvas>
        </Grid>
    </Viewbox>
</UserControl>

 

반응형

 

▶ CircularProgressBar.xaml.cs

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;

namespace TestProject
{
    /// <summary>
    /// 환형 진행바
    /// </summary>
    public partial class CircularProgressBar : UserControl
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Dependency Property
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Public

        #region 최소값 속성 - MinimumProperty

        /// <summary>
        /// 최소값 속성
        /// </summary>
        public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register
        (
            "Minimum",
            typeof(int),
            typeof(CircularProgressBar),
            new UIPropertyMetadata(1)
        );

        #endregion
        #region 최대값 속성 - MaximumProperty

        /// <summary>
        /// 최대값 속성
        /// </summary>
        public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register
        (
            "Maximum",
            typeof(int),
            typeof(CircularProgressBar),
            new UIPropertyMetadata(1)
        );

        #endregion
        #region 값 속성 - ValueProperty

        /// <summary>
        /// 값 속성
        /// </summary>
        public static readonly DependencyProperty ValueProperty = DependencyProperty.Register
        (
            "Value",
            typeof(int),
            typeof(CircularProgressBar),
            new UIPropertyMetadata(100)
        );

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 디스패처 타이머
        /// </summary>
        private readonly DispatcherTimer dispatcherTimer;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 최소값 - Minimum

        /// <summary>
        /// 최소값
        /// </summary>
        public int Minimum
        {
            get
            {
                return (int)GetValue(MinimumProperty);
            }
            set
            {
                SetValue(MinimumProperty, value);
            }
        }

        #endregion
        #region 최대값 - Maximum

        /// <summary>
        /// 최대값
        /// </summary>
        public int Maximum
        {
            get
            {
                return (int)GetValue(MaximumProperty);
            }
            set
            {
                SetValue(MaximumProperty, value);
            }
        }

        #endregion
        #region 값 - Value

        /// <summary>
        /// 값
        /// </summary>
        public int Value
        {
            get
            {
                return (int)GetValue(ValueProperty);
            }
            set
            {
                SetValue(ValueProperty, value);
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - CircularProgressBar()

        /// <summary>
        /// 생성자
        /// </summary>
        public CircularProgressBar()
        {
            InitializeComponent();

            this.dispatcherTimer = new DispatcherTimer(DispatcherPriority.ContextIdle, Dispatcher)
            {
                Interval = new TimeSpan(0, 0, 0, 0, 75)
            };

            IsVisibleChanged     += UserControl_IsVisibleChanged;
            this.canvas.Loaded   += canvas_Loaded;
            this.canvas.Unloaded += canvas_Unloaded;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Private

        #region 위치 설정하기 - SetPosition(dependencyObject, offset, indexOffSet, step)

        /// <summary>
        /// 위치 설정하기
        /// </summary>
        /// <param name="dependencyObject">의존 객체</param>
        /// <param name="offset">오프셋</param>
        /// <param name="indexOffSet">인덱스 오프셋</param>
        /// <param name="step">단계</param>
        private static void SetPosition(DependencyObject dependencyObject, double offset, double indexOffSet, double step)
        {
            dependencyObject.SetValue(Canvas.LeftProperty, 50 + (Math.Sin(offset + (indexOffSet * step)) * 50));
            dependencyObject.SetValue(Canvas.TopProperty , 50 + (Math.Cos(offset + (indexOffSet * step)) * 50));
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Instance
        //////////////////////////////////////////////////////////////////////////////// Private
        ////////////////////////////////////////////////////////////////////// Event

        #region 사용자 컨트롤 표시 여부 변경시 처리하기 - UserControl_IsVisibleChanged(sender, e)

        /// <summary>
        /// 사용자 컨트롤 표시 여부 변경시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void UserControl_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            bool isVisible = (bool)e.NewValue;

            if(isVisible)
            {
                Start();
            }
            else
            {
                Stop();
            }
        }

        #endregion
        #region 캔버스 로드시 처리하기 - canvas_Loaded(sender, e)

        /// <summary>
        /// 캔버스 로드시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void canvas_Loaded(object sender, RoutedEventArgs e)
        {
            const double offset = Math.PI;
            const double step   = Math.PI * 2 / 10.0;

            SetPosition(this.ellipse0, offset, 0.0, step);
            SetPosition(this.ellipse1, offset, 1.0, step);
            SetPosition(this.ellipse2, offset, 2.0, step);
            SetPosition(this.ellipse3, offset, 3.0, step);
            SetPosition(this.ellipse4, offset, 4.0, step);
            SetPosition(this.ellipse5, offset, 5.0, step);
            SetPosition(this.ellipse6, offset, 6.0, step);
            SetPosition(this.ellipse7, offset, 7.0, step);
            SetPosition(this.ellipse8, offset, 8.0, step);
        }

        #endregion
        #region 캔버스 언로드시 처리하기 - canvas_Unloaded(sender, e)

        /// <summary>
        /// 캔버스 언로드시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void canvas_Unloaded(object sender, RoutedEventArgs e)
        {
            Stop();
        }
        
        #endregion
        #region 디스패처 타이머 틱 처리하기 - dispatcherTimer_Tick(sender, e)

        /// <summary>
        /// 디스패처 타이머 틱 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void dispatcherTimer_Tick(object sender, EventArgs e)
        {
            this.rotateTransform.Angle = (this.rotateTransform.Angle + 36) % 360;
        }

        #endregion

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

        #region 시작하기 - Start()

        /// <summary>
        /// 시작하기
        /// </summary>
        private void Start()
        {
            this.dispatcherTimer.Tick += dispatcherTimer_Tick;

            this.dispatcherTimer.Start();
        }

        #endregion
        #region 중단하기 - Stop()

        /// <summary>
        /// 중단하기
        /// </summary>
        private void Stop()
        {
            this.dispatcherTimer.Stop();

            this.dispatcherTimer.Tick -= dispatcherTimer_Tick;
        }

        #endregion
    }
}

 

▶ LoadingPanel.xaml

<UserControl x:Class="TestProject.LoadingPanel"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:TestProject" 
    xmlns:theme="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Classic">
    <UserControl.Resources>
        <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverterKey" />
        <LinearGradientBrush x:Key="PanelBackgroundLinearGradientBrushKey"
            StartPoint="0.5 0"
            EndPoint="0.5 1">
            <GradientStop Offset="0" Color="#ff1b1b1b" />
            <GradientStop Offset="1" Color="Black"     />
        </LinearGradientBrush>
        <Style x:Key="BasicButtonStyleKey" TargetType="{x:Type Button}">
            <Setter Property="BorderThickness"            Value="3"                                                             />
            <Setter Property="BorderBrush"                Value="{x:Static theme:ClassicBorderDecorator.ClassicBorderBrush}"    />
            <Setter Property="Background"                 Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"     />
            <Setter Property="Foreground"                 Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" />
            <Setter Property="Padding"                    Value="0 0 1 1" />
            <Setter Property="HorizontalContentAlignment" Value="Center"  />
            <Setter Property="VerticalContentAlignment"   Value="Center"  />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <theme:ClassicBorderDecorator Name="ContentContainer"
                            BorderStyle="None"
                            BorderThickness="0"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            Background="{TemplateBinding Background}"
                            SnapsToDevicePixels="True">
                            <ContentPresenter
                                HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                Margin="{TemplateBinding Padding}"
                                SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                RecognizesAccessKey="True" />
                        </theme:ClassicBorderDecorator>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsKeyboardFocused" Value="True">
                                <Setter
                                    TargetName="ContentContainer"
                                    Property="BorderStyle"
                                    Value="RaisedFocused" />
                            </Trigger>
                            <Trigger Property="IsDefaulted" Value="True">
                                <Setter
                                    TargetName="ContentContainer"
                                    Property="BorderStyle"
                                    Value="RaisedFocused" />
                            </Trigger>
                            <Trigger Property="IsPressed" Value="True">
                                <Setter
                                    TargetName="ContentContainer"
                                    Property="BorderStyle"
                                    Value="RaisedPressed" />
                            </Trigger>
                            <Trigger Property="ToggleButton.IsChecked" Value="True">
                                <Setter
                                    TargetName="ContentContainer"
                                    Property="BorderStyle"
                                    Value="RaisedPressed" />
                            </Trigger>
                            <Trigger Property="IsEnabled" Value="False">
                                <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <Style x:Key="CloseButtonStyleKey" BasedOn="{StaticResource BasicButtonStyleKey}" TargetType="Button">
            <Setter Property="VerticalAlignment" Value="Top"      />
            <Setter Property="Margin"            Value="15,7"     />
            <Setter Property="Background"        Value="{x:Null}" />
            <Setter Property="Cursor"            Value="Hand"     />
            <Setter Property="Foreground"        Value="White"    />
            <Setter Property="FontFamily"        Value="Verdana"  />
            <Setter Property="FontSize"          Value="9"        />
            <Setter Property="FontWeight"        Value="Bold"     />
        </Style>
        <Style x:Key="MessageTextBlockStyleKey" TargetType="{x:Type TextBlock}">
            <Setter Property="HorizontalAlignment" Value="Left"             />
            <Setter Property="VerticalAlignment"   Value="Top"              />
            <Setter Property="Margin"              Value="0 11 0 0"         />
            <Setter Property="SnapsToDevicePixels" Value="True"             />
            <Setter Property="TextWrapping"        Value="WrapWithOverflow" />
            <Setter Property="FontFamily"          Value="Arial"            />
            <Setter Property="FontSize"            Value="16"               />
            <Setter Property="FontWeight"          Value="Bold"             />
        </Style>
        <Style x:Key="SubsidaryMessageTextBlockStyleKey" TargetType="{x:Type TextBlock}">
            <Setter Property="HorizontalAlignment" Value="Left"  />
            <Setter Property="VerticalAlignment"   Value="Top"   />
            <Setter Property="Margin"              Value="0,5"   />
            <Setter Property="SnapsToDevicePixels" Value="True"  />
            <Setter Property="TextWrapping"        Value="Wrap"  />
            <Setter Property="FontFamily"          Value="Arial" />
            <Setter Property="FontSize"            Value="12"    />
        </Style>
    </UserControl.Resources>
    <DockPanel Background="{StaticResource PanelBackgroundLinearGradientBrushKey}"
        Visibility="{Binding RelativeSource={RelativeSource FindAncestor,
            AncestorType={x:Type UserControl}},
            Path=IsLoading,
            Mode=OneWay,
            Converter={StaticResource BooleanToVisibilityConverterKey}}">
        <Path DockPanel.Dock="Top"
            Margin="0 0.25 0 0"
            Height="1"
            Stretch="Fill"
            Stroke="Black"
            Data="M 0 44.956 L 312.00641 44.956" />
        <Path DockPanel.Dock="Top"
            Margin="0 0.25 0 0"
            Height="1"
            Stretch="Fill"
            Stroke="#ff2f2f2f"
            Data="M 0 44.956 L 312.00641 44.956" />
        <Button Name="closeBitton" DockPanel.Dock="Right"
            Style="{StaticResource CloseButtonStyleKey}"
            ToolTip="Close"
            Content="Close X" />
        <local:CircularProgressBar DockPanel.Dock="Left"
            HorizontalAlignment="Left"
            VerticalAlignment="Top"
            Margin="18 10"
            Height="45" />
        <StackPanel VerticalAlignment="Top">
            <TextBlock
                Style="{StaticResource MessageTextBlockStyleKey}" 
                Foreground="#ffa1c3d2"
                Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=Message}" />
            <TextBlock
                Style="{StaticResource SubsidaryMessageTextBlockStyleKey}" 
                Foreground="#ffa1c3d2"
                Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=SubsidaryMessage}" />
        </StackPanel>
    </DockPanel>
</UserControl>

 

▶ LoadingPanel.xaml.cs

using System.Windows;
using System.Windows.Input;

namespace TestProject
{
    /// <summary>
    /// 로딩 패널
    /// </summary>
    public partial class LoadingPanel
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Dependency Property
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Public

        #region 로딩 여부 속성 - IsLoadingProperty

        /// <summary>
        /// 로딩 여부 속성
        /// </summary>
        public static readonly DependencyProperty IsLoadingProperty = DependencyProperty.Register
        (
            "IsLoading",
            typeof(bool),
            typeof(LoadingPanel),
            new UIPropertyMetadata(false)
        );

        #endregion
        #region 메시지 속성 - MessageProperty

        /// <summary>
        /// 메시지 속성
        /// </summary>
        public static readonly DependencyProperty MessageProperty = DependencyProperty.Register
        (
            "Message",
            typeof(string),
            typeof(LoadingPanel),
            new UIPropertyMetadata("로딩중...")
        );

        #endregion
        #region 보조 메시지 속성 - SubsidaryMessageProperty

        /// <summary>
        /// 보조 메시지 속성
        /// </summary>
        public static readonly DependencyProperty SubsidaryMessageProperty = DependencyProperty.Register
        (
            "SubsidaryMessage",
            typeof(string),
            typeof(LoadingPanel),
            new UIPropertyMetadata(string.Empty)
        );

        #endregion
        #region 패널 닫기 명령 속성 - ClosePanelCommandProperty

        /// <summary>
        /// 패널 닫기 명령 속성
        /// </summary>
        public static readonly DependencyProperty ClosePanelCommandProperty = DependencyProperty.Register
        (
            "ClosePanelCommand",
            typeof(ICommand),
            typeof(LoadingPanel)
        );

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 로딩 여부 - IsLoading

        /// <summary>
        /// 로딩 여부
        /// </summary>
        public bool IsLoading
        {
            get
            {
                return (bool)GetValue(IsLoadingProperty);
            }
            set
            {
                SetValue(IsLoadingProperty, value);
            }
        }

        #endregion
        #region 메시지 - Message

        /// <summary>
        /// 메시지
        /// </summary>
        public string Message
        {
            get
            {
                return (string)GetValue(MessageProperty);
            }
            set
            {
                SetValue(MessageProperty, value);
            }
        }

        #endregion
        #region 보조 메시지 - SubsidaryMessage

        /// <summary>
        /// 보조 메시지
        /// </summary>
        public string SubsidaryMessage
        {
            get
            {
                return (string)GetValue(SubsidaryMessageProperty);
            }
            set
            {
                SetValue(SubsidaryMessageProperty, value);
            }
        }

        #endregion
        #region 패널 닫기 명령 - ClosePanelCommand

        /// <summary>
        /// 패널 닫기 명령
        /// </summary>
        public ICommand ClosePanelCommand
        {
            get
            {
                return (ICommand)GetValue(ClosePanelCommandProperty);
            }
            set
            {
                SetValue(ClosePanelCommandProperty, value);
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - LoadingPanel()

        /// <summary>
        /// 생성자
        /// </summary>
        public LoadingPanel()
        {
            InitializeComponent();

            this.closeBitton.Click += closeButton_Click;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region 닫기 버튼 클릭시 처리하기 - closeButton_Click(sender, e)

        /// <summary>
        /// 닫기 버튼 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void closeButton_Click(object sender, RoutedEventArgs e)
        {
            ClosePanelCommand?.Execute(null);
        }

        #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:local="clr-namespace:TestProject"
    Width="800"
    Height="600"
    Title="UserControl 클래스 : 로딩 패널 사용하기"
    Background="Orange"
    FontFamily="나눔고딕코딩"
    FontSize="16">
    <Grid>
        <DockPanel
            HorizontalAlignment="Center"
            VerticalAlignment="Top">
            <StackPanel
                Margin="10"
                Orientation="Horizontal">
                <Button Name="btnShow"
                    Width="100"
                    Height="30"
                    Content="패널 표시"
                    Command="{Binding ShowPanelCommand}" />
                <Button Name="btnHide"
                    Margin="10 0 0 0"
                    Width="100"
                    Height="30"
                    Content="패널 숨김"
                    Command="{Binding HidePanelCommand}" />
                <Button Name="btnChange"
                    Width="100"
                    Margin="10 0 0 0"
                    Height="30"
                    Content="메시지 변경"
                    Command="{Binding ChangeMessageCommand}" />
            </StackPanel>
        </DockPanel>
        <Grid VerticalAlignment="Bottom">
            <local:LoadingPanel
                IsLoading="{Binding IsPanelLoading}"
                Message="{Binding PanelMessage}"
                SubsidaryMessage="{Binding PanelSubsidaryMessage}" 
                ClosePanelCommand="{Binding PanelCloseCommand}" />
        </Grid>
    </Grid>
</Window>

 

▶ MainWindow.xaml.cs

using System;
using System.ComponentModel;
using System.Windows.Input;

namespace TestProject
{
    /// <summary>
    /// 메인 윈도우
    /// </summary>
    public partial class MainWindow : INotifyPropertyChanged
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Event
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 속성 변경시 이벤트 - PropertyChanged

        /// <summary>
        /// 속성 변경시 이벤트
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 패널 로딩 여부
        /// </summary>
        private bool isPanelLoading;

        /// <summary>
        /// 패널 메시지
        /// </summary>
        private string panelMessage = "패널 메시지";

        /// <summary>
        /// 패널 보조 메시지
        /// </summary>
        private string panelSubsidaryMessage = "패널 보조 메시지";

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 패널 표시 명령 - ShowPanelCommand

        /// <summary>
        /// 패널 표시 명령
        /// </summary>
        public ICommand ShowPanelCommand
        {
            get
            {
                return new DelegateCommand(() => { IsPanelLoading = true; });
            }
        }

        #endregion
        #region 패널 숨김 명령 - HidePanelCommand

        /// <summary>
        /// 패널 숨김 명령
        /// </summary>
        public ICommand HidePanelCommand
        {
            get
            {
                return new DelegateCommand(() => { IsPanelLoading = false; });
            }
        }

        #endregion
        #region 메시지 변경 명령 - ChangeMessageCommand

        /// <summary>
        /// 메시지 변경 명령
        /// </summary>
        public ICommand ChangeMessageCommand
        {
            get
            {
                return new DelegateCommand(() => { PanelSubsidaryMessage = $"메시지 : {DateTime.Now}"; });
            }
        }

        #endregion

        #region 패널 로딩 여부 - IsPanelLoading

        /// <summary>
        /// 패널 로딩 여부
        /// </summary>
        public bool IsPanelLoading
        {
            get
            {
                return this.isPanelLoading;
            }
            set
            {
                this.isPanelLoading = value;

                FirePropertyChangedEvent("IsPanelLoading");
            }
        }

        #endregion
        #region 패널 메시지 - PanelMessage

        /// <summary>
        /// 패널 메시지
        /// </summary>
        public string PanelMessage
        {
            get
            {
                return this.panelMessage;
            }
            set
            {
                this.panelMessage = value;

                FirePropertyChangedEvent("PanelMessage");
            }
        }

        #endregion
        #region 패널 보조 메시지 - PanelSubsidaryMessage

        /// <summary>
        /// 패널 보조 메시지
        /// </summary>
        public string PanelSubsidaryMessage
        {
            get
            {
                return this.panelSubsidaryMessage;
            }
            set
            {
                this.panelSubsidaryMessage = value;

                FirePropertyChangedEvent("PanelSubsidaryMessage");
            }
        }

        #endregion
        #region 패널 닫기 명령 - PanelCloseCommand

        /// <summary>
        /// 패널 닫기 명령
        /// </summary>
        public ICommand PanelCloseCommand
        {
            get
            {
                return new DelegateCommand(() => { IsPanelLoading = false; });
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - MainWindow()

        /// <summary>
        /// 생성자
        /// </summary>
        public MainWindow()
        {
            InitializeComponent();

            DataContext = this;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Protected

        #region 속성 변경시 이벤트 발생시키기 - FirePropertyChangedEvent(propertyName)

        /// <summary>
        /// 속성 변경시 이벤트 발생시키기
        /// </summary>
        /// <param name="propertyName">속성명</param>
        protected void FirePropertyChangedEvent(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion
    }
}
728x90
반응형
그리드형(광고전용)
Posted by 사용자 icodebroker

댓글을 달아 주세요