■ UserControl 클래스를 사용해 로딩 패널을 만드는 방법을 보여준다.
▶ CommandManager.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
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 } } |
▶ DelegateCommand.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
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 } } |
▶ CircularProgressBar.xaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
<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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 |
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
<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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
<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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
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 } } |