[C#/WPF] WPF 타블렛 지원 비활성화하기
■ WPF 타블렛 지원을 비활성화하는 방법을 보여준다. WPF는 Windows 7 터치 입력 처리를 기본적으로 지원한다. 지원은 OnStylusDown, OnStylusUp 및 OnStylusMove 이벤트와 같은
■ WPF 타블렛 지원을 비활성화하는 방법을 보여준다. WPF는 Windows 7 터치 입력 처리를 기본적으로 지원한다. 지원은 OnStylusDown, OnStylusUp 및 OnStylusMove 이벤트와 같은
■ InkPresenter 클래스를 사용해 스트로크 회전 어도너를 만드는 방법을 보여준다. ▶ RotatingStrokesAdorner.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 |
using System; using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Documents; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Media; using System.Windows.Shapes; namespace TestProject { /// <summary> /// 스트로크 회전 어도너 /// </summary> public class RotatingStrokesAdorner : Adorner { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 핸들 마진 /// </summary> private const int HANDLE_MARGIN = 10; /// <summary> /// 회전 핸들 썸 /// </summary> private Thumb rotateHandleThumb; /// <summary> /// 외곽선 경로 /// </summary> private Path outlinePath; /// <summary> /// 비주얼 컬렉션 /// </summary> private VisualCollection visualCollection; /// <summary> /// 중심 포인트 /// </summary> private Point centerPoint; /// <summary> /// 마지막 각도 /// </summary> private double lastAngle; /// <summary> /// 회전 변환 /// </summary> private RotateTransform rotateTransform; /// <summary> /// 스트로크 테두리 사각형 /// </summary> private Rect strokeBoundRectangle = Rect.Empty; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 장식 스트로크 컬렉션 - AdornedStrokeCollection /// <summary> /// 장식 스트로크 컬렉션 /// </summary> private StrokeCollection AdornedStrokeCollection { get { return ((InkPresenter)AdornedElement).Strokes; } } #endregion #region 비주얼 자식 카운트 - VisualChildrenCount /// <summary> /// 비주얼 자식 카운트 /// </summary> protected override int VisualChildrenCount { get { return this.visualCollection.Count; } } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - RotatingStrokesAdorner(adornedElement) /// <summary> /// 생성자 /// </summary> /// <param name="adornedElement">장식 엘리먼트</param> public RotatingStrokesAdorner(UIElement adornedElement) : base(adornedElement) { this.visualCollection = new VisualCollection(this); this.rotateHandleThumb = new Thumb(); this.rotateHandleThumb.Width = 20; this.rotateHandleThumb.Height = 20; this.rotateHandleThumb.Background = Brushes.Blue; this.rotateHandleThumb.Cursor = Cursors.SizeNWSE; this.rotateHandleThumb.DragDelta += rotateHandleThumb_DragDelta; this.rotateHandleThumb.DragCompleted += rotateHandleThumb_DragCompleted; this.outlinePath = new Path(); this.outlinePath.StrokeThickness = 1; this.outlinePath.Stroke = Brushes.Blue; this.visualCollection.Add(this.outlinePath ); this.visualCollection.Add(this.rotateHandleThumb); this.strokeBoundRectangle = AdornedStrokeCollection.GetBounds(); } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Protected #region 비주얼 자식 구하기 - GetVisualChild(index) /// <summary> /// 비주얼 자식 구하기 /// </summary> /// <param name="index">인덱스</param> /// <returns>비주얼 자식</returns> protected override Visual GetVisualChild(int index) { return this.visualCollection[index]; } #endregion #region 배열하기 (오버라이드) - ArrangeOverride(finalSize) /// <summary> /// 배열하기 (오버라이드) /// </summary> /// <param name="finalSize">최종 크기</param> /// <returns>배열 크기</returns> protected override Size ArrangeOverride(Size finalSize) { if(this.strokeBoundRectangle.IsEmpty) { return finalSize; } this.centerPoint = new Point ( this.strokeBoundRectangle.X + this.strokeBoundRectangle.Width / 2, this.strokeBoundRectangle.Y + this.strokeBoundRectangle.Height / 2 ); Rect handleRectangle = new Rect ( this.strokeBoundRectangle.X, this.strokeBoundRectangle.Y - (this.strokeBoundRectangle.Height / 2 + HANDLE_MARGIN), this.strokeBoundRectangle.Width, this.strokeBoundRectangle.Height ); if(this.rotateTransform != null) { handleRectangle.Transform(this.rotateTransform.Value); } this.rotateHandleThumb.Arrange(handleRectangle); this.outlinePath.Data = new RectangleGeometry(this.strokeBoundRectangle); this.outlinePath.Arrange(new Rect(finalSize)); return finalSize; } #endregion ////////////////////////////////////////////////////////////////////////////////////////// Private #region 회전 핸들 썸 드래그 델타 처리하기 - rotateHandleThumb_DragDelta(sender, e) /// <summary> /// 회전 핸들 썸 드래그 델타 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void rotateHandleThumb_DragDelta(object sender, DragDeltaEventArgs e) { Point point = Mouse.GetPosition(this); double deltaX = point.X - this.centerPoint.X; double deltaY = point.Y - this.centerPoint.Y; if(deltaY.Equals(0)) { return; } double tangent = deltaX / deltaY; double angle = Math.Atan(tangent); angle = angle * 180 / Math.PI; if(deltaY > 0) { angle = 180 - Math.Abs(angle); } if(deltaX < 0) { angle = -Math.Abs(angle); } else { angle = Math.Abs(angle); } if(double.IsNaN(angle)) { return; } this.rotateTransform = new RotateTransform(angle, this.centerPoint.X, this.centerPoint.Y); this.outlinePath.RenderTransform = this.rotateTransform; } #endregion #region 회전 핸들 썸 드래그 완료시 처리하기 - rotateHandleThumb_DragCompleted(sender, e) /// <summary> /// 회전 핸들 썸 드래그 완료시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void rotateHandleThumb_DragCompleted(object sender, DragCompletedEventArgs e) { if(this.rotateTransform == null) { return; } Matrix matrix = new Matrix(); matrix.RotateAt(this.rotateTransform.Angle - this.lastAngle, this.centerPoint.X, this.centerPoint.Y); AdornedStrokeCollection.Transform(matrix, true); this.lastAngle = this.rotateTransform.Angle; InvalidateArrange(); } #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 |
<Window x:Class="TestProject.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="800" Height="600" Title="TestProject" FontFamily="나눔고딕코딩" FontSize="16"> <InkPresenter Name="inkPresenter"> <InkPresenter.Strokes> ALMDAwRIEEU1BQE4GSAyCQD0/wIB6SI6RTMJAPifAgFaIDpFOAgA/gMAAACAfxEAAIA/ HwkRAAAAAAAA8D8KlwE1h/CPd4SB4NA4OicCjcGjcClcDj8Lh8DgUSkUmmU6nUmoUuk 0ukUCQKVyehz+rzuly+bzORx+BReRQ+RTaRCH8JyXhPbgcPicPh8Pg8Oh0qk1SoVGrV Oo0mi0Xi8rm9Xr9Dqc/p87pc/k8XicHicOj1CoVKtVmv1GqUaiUHlYg8el4akXK7m7T cSJgQgghEyym5zx6+PACk4dhPwg/fhCbxY8dp4p2tqnqxyvbPO85z1X1aswhvCd94Tq 55DRUGi4+Tk6OLn4KLkoOejo6ig5KTioOPCD9LlHmrzNxMRCCc3ec8+fe4AKQBmE/Cw 9+FkPNvlOdkrYsWa+acp3Z8erOIT8JaX4S6+FbFilbHNvvPXNJbFqluxghKc5DkwrVF GEEIJ1w5eLKYAKShuF+Dnr4Oa8HVHXNPFFFFho8VFkqsMRYuuvJxiF+F9r4Xx8HFiqs FNcirnweDw9+LvvvixdV0+GhONmlj3wjNOcSCEYTnfLy4oA </InkPresenter.Strokes> </InkPresenter> </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 |
using System.Windows; using System.Windows.Documents; namespace TestProject { /// <summary> /// 메인 윈도우 /// </summary> public partial class MainWindow : Window { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 어도너 레이어 /// </summary> private AdornerLayer adornerLayer; /// <summary> /// 어도너 /// </summary> private Adorner adorner; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - MainWindow() /// <summary> /// 생성자 /// </summary> public MainWindow() { InitializeComponent(); Loaded += Window_Loaded; } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Private #region 윈도우 로드시 처리하기 - Window_Loaded(sender, e) /// <summary> /// 윈도우 로드시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void Window_Loaded(object sender, RoutedEventArgs e) { this.adornerLayer = AdornerLayer.GetAdornerLayer(this.inkPresenter); this.adorner = new RotatingStrokesAdorner(this.inkPresenter); this.adornerLayer.Add(this.adorner); } #endregion } } |
TestProject.zip
■ InkPresenter 클래스를 사용해 잉크를 회전/복사하는 방법을 보여준다. ▶ 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 |
<Window x:Class="TestProject.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="800" Height="600" Title="TestProject" FontFamily="나눔고딕코딩" FontSize="16"> <Grid Margin="10"> <Grid.RowDefinitions> <RowDefinition Height="*" /> <RowDefinition Height="10" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="10" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <InkCanvas Name="sourceInkCanvas" Grid.Row="0" Grid.Column="0" Background="LightBlue" /> <Border Name="targetBorder" Grid.Row="0" Grid.Column="2" Background="LightGreen" ClipToBounds="True"> <InkPresenter Name="targetInkPresenter" /> </Border> <Button Name="copyAndRotateStrokeButton" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3" HorizontalAlignment="Center" Padding="10 0 10 0" Height="30" Content="스트로크 회전 및 복사하기" /> </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 |
using System.Windows; using System.Windows.Ink; using System.Windows.Media; namespace TestProject { /// <summary> /// 메인 윈도우 /// </summary> public partial class MainWindow : Window { //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - MainWindow() /// <summary> /// 생성자 /// </summary> public MainWindow() { InitializeComponent(); this.copyAndRotateStrokeButton.Click += copyAndRotateStrokeButton_Click; } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Private #region 스트로크 회전 및 복사하기 버튼 클릭시 처리하기 - copyAndRotateStrokeButton_Click(sender, e) /// <summary> /// 스트로크 회전 및 복사하기 버튼 클릭시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void copyAndRotateStrokeButton_Click(object sender, RoutedEventArgs e) { StrokeCollection strokeCollection = this.sourceInkCanvas.Strokes.Clone(); Matrix matrix = new Matrix(); Point centerPoint = new Point(this.targetBorder.ActualWidth / 2, targetBorder.ActualHeight / 2); matrix.RotateAt(90, centerPoint.X, centerPoint.Y); strokeCollection.Transform(matrix, false); this.targetInkPresenter.Strokes = strokeCollection; } #endregion } } |
TestProject.zip
■ InkCanvas 엘리먼트의 DefaultDrawingAttributes/EditingMode/Strokes 속성을 사용해 바인딩하는 방법을 보여준다. ▶ 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 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 |
<Window x:Class="TestProject.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="800" Height="600" Title="TestProject" FontFamily="나눔고딕코딩" FontSize="16"> <Grid Margin="10"> <Grid.Resources> <x:Array x:Key="InkCanvasEditingModeArrayKey" Type="{x:Type InkCanvasEditingMode}"> <x:Static Member="InkCanvasEditingMode.Ink" /> <x:Static Member="InkCanvasEditingMode.Select" /> <x:Static Member="InkCanvasEditingMode.EraseByPoint" /> <x:Static Member="InkCanvasEditingMode.EraseByStroke" /> </x:Array> <x:Array x:Key="DrawingAttributesArrayKey" Type="{x:Type DrawingAttributes}"> <DrawingAttributes Width="3" Height="3" Color="Black" FitToCurve="true" /> <DrawingAttributes Width="5" Height="5" Color="Blue" FitToCurve="false" /> <DrawingAttributes Width="7" Height="7" Color="Red" FitToCurve="true" /> </x:Array> <DataTemplate DataType="{x:Type DrawingAttributes}"> <Border Width="80" Height="20"> <Border.Background > <SolidColorBrush Color="{Binding Path=Color}" /> </Border.Background> </Border> </DataTemplate> </Grid.Resources> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="10" /> <ColumnDefinition Width="*" /> <ColumnDefinition Width="10" /> <ColumnDefinition Width="Auto" /> </Grid.ColumnDefinitions> <Border Grid.Column="0" BorderThickness="2" BorderBrush="Black"> <InkCanvas Name="inkCanvas1" Background="LightGray" DefaultDrawingAttributes="{Binding ElementName=drawingAttributesListBox, Path=SelectedItem}" EditingMode="{Binding ElementName=editingModeListBox, Path=SelectedItem}" /> </Border> <Border Grid.Column="2" BorderThickness="2" BorderBrush="Black"> <InkCanvas Background="LightBlue" DefaultDrawingAttributes="{Binding ElementName=inkCanvas1, Path=DefaultDrawingAttributes}" EditingMode="{Binding ElementName=inkCanvas1, Path=EditingMode}" Strokes="{Binding ElementName=inkCanvas1, Path=Strokes}"> <InkCanvas.LayoutTransform> <ScaleTransform ScaleX="-1" ScaleY="1" /> </InkCanvas.LayoutTransform> </InkCanvas> </Border> <StackPanel Grid.Column="4" VerticalAlignment="Center"> <ListBox Name="editingModeListBox" Height="100" Width="100" ItemsSource="{StaticResource InkCanvasEditingModeArrayKey}" /> <ListBox Name="drawingAttributesListBox" Margin="0 10 0 0" Height="100" Width="100" ItemsSource="{StaticResource DrawingAttributesArrayKey}" /> </StackPanel> </Grid> </Window> |
TestProject.zip
■ InkCanvas 엘리먼트의 DefaultDrawingAttributes 속성을 사용해 바인딩하는 방법을 보여준다. ▶ 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 48 49 50 51 52 53 54 |
<Window x:Class="TestProject.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="800" Height="600" Title="TestProject" FontFamily="나눔고딕코딩" FontSize="16"> <Grid Margin="10"> <Grid.Resources> <x:Array x:Key="DrawingAttributesArrayKey" Type="{x:Type DrawingAttributes}"> <DrawingAttributes Width="3" Height="3" Color="Black" FitToCurve="true" /> <DrawingAttributes Width="5" Height="5" Color="Blue" FitToCurve="false" /> <DrawingAttributes Width="7" Height="7" Color="Red" FitToCurve="true" /> </x:Array> <DataTemplate DataType="{x:Type DrawingAttributes}"> <Border Width="80" Height="20"> <Border.Background > <SolidColorBrush Color="{Binding Path=Color}" /> </Border.Background> </Border> </DataTemplate> </Grid.Resources> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="10" /> <ColumnDefinition Width="Auto" /> </Grid.ColumnDefinitions> <InkCanvas Name="inkCanvas1" Grid.Column="0" Background="LightGreen" DefaultDrawingAttributes="{Binding ElementName=drawingAttributesListBox, Path=SelectedItem}"> </InkCanvas> <ListBox Name="drawingAttributesListBox" Grid.Column="2" Height="100" Width="100" ItemsSource="{StaticResource DrawingAttributesArrayKey}" /> </Grid> </Window> |
TestProject.zip
■ InkCanvas 엘리먼트의 Strokes 속성을 사용해 바인딩하는 방법을 보여준다. ▶ 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 |
<Window x:Class="TestProject.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="800" Height="600" Title="TestProject" FontFamily="나눔고딕코딩" FontSize="16"> <Grid Margin="10"> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="10" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Border Grid.Column="0" BorderThickness="1" BorderBrush="Black"> <InkCanvas Name="inkCanvas1" Background="LightGray" /> </Border> <Border Grid.Column="2" BorderThickness="1" BorderBrush="Black"> <InkCanvas Name="inkCanvas2" Background="LightBlue" Strokes="{Binding ElementName=inkCanvas1, Path=Strokes}"> <InkCanvas.LayoutTransform> <ScaleTransform ScaleX="-1" ScaleY="1" /> </InkCanvas.LayoutTransform> </InkCanvas> </Border> </Grid> </Window> |
TestProject.zip
■ InkCanvas 클래스에서 잉크 드래그 & 드롭을 사용하는 방법을 보여준다. ▶ 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 |
<Window x:Class="TestProject.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="800" Height="600" Title="TestProject" FontFamily="나눔고딕코딩" FontSize="16"> <Grid Margin="10"> <Grid.RowDefinitions> <RowDefinition Height="*" /> <RowDefinition Height="10" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="10" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Border Grid.Row="0" Grid.Column="0" BorderThickness="1" BorderBrush="Black"> <InkCanvas Name="inkCanvas1" Background="AliceBlue" AllowDrop="True" /> </Border> <Border Grid.Row="0" Grid.Column="2" BorderThickness="1" BorderBrush="Black"> <InkCanvas Name="inkCanvas2" Background="Beige" AllowDrop="True" /> </Border> <CheckBox Name="selectionModeCheckBox" Grid.Row="2" Padding="10" VerticalContentAlignment="Center" Content="선택 모드" /> </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 |
using System.IO; using System.Windows; using System.Windows.Controls; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Media; namespace TestProject { /// <summary> /// 메인 윈도우 /// </summary> public partial class MainWindow : Window { //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - MainWindow() /// <summary> /// 생성자 /// </summary> public MainWindow() { InitializeComponent(); this.inkCanvas1.PreviewMouseDown += inkCanvas_PreviewMouseDown; this.inkCanvas1.Drop += inkCanvas_Drop; this.inkCanvas2.PreviewMouseDown += inkCanvas_PreviewMouseDown; this.inkCanvas2.Drop += inkCanvas_Drop; this.selectionModeCheckBox.Checked += selectionModeCheckBox_Checked; this.selectionModeCheckBox.Unchecked += selectionModeCheckBox_Unchecked; } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Private //////////////////////////////////////////////////////////////////////////////// Event #region 잉크 캔버스 프리뷰 마우스 DOWN 처리하기 - inkCanvas_PreviewMouseDown(sender, e) /// <summary> /// 잉크 캔버스 프리뷰 마우스 DOWN 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void inkCanvas_PreviewMouseDown(object sender, MouseEventArgs e) { InkCanvas inkCanvas = sender as InkCanvas; Point point = e.GetPosition(inkCanvas); if(inkCanvas.HitTestSelection(point) == InkCanvasSelectionHitResult.Selection) { StrokeCollection selectedStrokeCollection = inkCanvas.GetSelectedStrokes(); StrokeCollection strokeCollectionToMove = selectedStrokeCollection.Clone(); Rect inkBoundRectangle = strokeCollectionToMove.GetBounds(); TranslateStrokeCollection(strokeCollectionToMove, -inkBoundRectangle.X, -inkBoundRectangle.Y); MemoryStream memoryStream = new MemoryStream(); strokeCollectionToMove.Save(memoryStream); DataObject dataObject = new DataObject(StrokeCollection.InkSerializedFormat, memoryStream); DragDropEffects effects = DragDrop.DoDragDrop(inkCanvas, dataObject, DragDropEffects.Move); if((effects & DragDropEffects.Move) == DragDropEffects.Move) { inkCanvas.Strokes.Remove(selectedStrokeCollection); } } } #endregion #region 잉크 캔버스 DROP 처리하기 - inkCanvas_Drop(sender, e) /// <summary> /// 잉크 캔버스 DROP 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void inkCanvas_Drop(object sender, DragEventArgs e) { InkCanvas inkCanvas = sender as InkCanvas; MemoryStream memoryStream = (MemoryStream)e.Data.GetData(StrokeCollection.InkSerializedFormat); memoryStream.Position = 0; StrokeCollection strokeCollection = new StrokeCollection(memoryStream); Point point = e.GetPosition(inkCanvas); TranslateStrokeCollection(strokeCollection, point.X, point.Y); inkCanvas.Strokes.Add(strokeCollection); inkCanvas.Select(strokeCollection); } #endregion #region 선택 모드 체크 박스 체크시 처리하기 - selectionModeCheckBox_Checked(sender, e) /// <summary> /// 선택 모드 체크 박스 체크시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void selectionModeCheckBox_Checked(object sender, RoutedEventArgs e) { this.inkCanvas1.EditingMode = InkCanvasEditingMode.Select; this.inkCanvas2.EditingMode = InkCanvasEditingMode.Select; } #endregion #region 선택 모드 체크 박스 체크 해제시 처리하기 - selectionModeCheckBox_Unchecked(sender, e) /// <summary> /// 선택 모드 체크 박스 체크 해제시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void selectionModeCheckBox_Unchecked(object sender, RoutedEventArgs e) { this.inkCanvas1.EditingMode = InkCanvasEditingMode.Ink; this.inkCanvas2.EditingMode = InkCanvasEditingMode.Ink; } #endregion //////////////////////////////////////////////////////////////////////////////// Function #region 스트로크 컬렉션 이동하기 - TranslateStrokeCollection(strokeCollection, x, y) /// <summary> /// 스트로크 컬렉션 이동하기 /// </summary> /// <param name="strokeCollection">스트로크 컬렉션</param> /// <param name="x">X</param> /// <param name="y">Y</param> private void TranslateStrokeCollection(StrokeCollection strokeCollection, double x, double y) { Matrix matrix = new Matrix(); matrix.Translate(x, y); strokeCollection.Transform(matrix, false); } #endregion } } |
TestProject.zip
■ UIElement 클래스를 사용해 잉크 입력 컨트롤에서 잉크를 지우는 방법을 보여준다. ▶ InkControl.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 284 285 286 287 288 289 |
using System.Windows; using System.Windows.Controls; using System.Windows.Ink; using System.Windows.Input; namespace TestProject { /// <summary> /// 잉크 컨트롤 /// </summary> public class InkControl : Label { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 증분 스트로크 히트 테스터 /// </summary> private IncrementalStrokeHitTester hitTester; /// <summary> /// 잉크 프리젠터 /// </summary> private InkPresenter presenter; /// <summary> /// 스트로크 문자열 /// </summary> private string strokeString = "ALwHAxdIEETLgIgERYQBGwIAJAFGhAEbAgAkAQUBOBkgMgkA9P8CAekiOkUzCQD4n" + "wIBWiA6RTgIAP4DAAAAgH8RAACAPx8JEQAAAAAAAPA/CiUHh/A6N4HR0AivFX8Vs" + "IfsiuyLSaIeDSLwabiHm0GgUDi+KZkACjsQh/A9t4IC5VJpfLhaIxyxXIh7Dncnh" + "+6e7qODwoERlPAw8EpGoJAgh61IKjCYXBYDA4DAIHF67KIHAAojB4fwMteBn+RKB" + "lziaIfwWTeCwePqbM8WgIeeQCDQOFRvcIAKNA+H8B8XgQHkUbjQTTnGuaZns3l4h" + "/DWt4a0YKBBOA94D6HRCAiGnp5CS8LExMLB1tOgYIAKUBOH8KnXhU7lMold+tcbi" + "kChkqu2EtPYxp9bmYCH8HDHg4ZhMIwRyMHH+4Jt8nleX8c0/D/AkYwxJGiHkkQgM" + "Ch9CqcFhMDQCBwWAwuR2eAACmgdh/EpF4lA6XMUfhMXgMHgVDxBFpRKpZII5EINA" + "OA64M+J4Lw1CIoAh/B2x4PS4bQodAopEI5IJBki4waEx2Qy+dy+ayHgleEmmHH8c" + "e3MZOCGw5TWd3CwsHAwMCgRAEAgElKwOHZKBApaGIfxezeL0uN02N8IzwaGEpNIJ" + "ZxHnELyOj0GfyuU6FgmhplIgIfwYgeDHeaI1vjOtZgcHgHAYb9hUCgEFgsPm1xnM" + "ZkYhsnYJgZeZh4uAgCgnSBIOJv4OAgwCmkgh/GrR41X4dGoRJL9EKra5HKY7IZ3C" + "4fj/M06olSoU8kkehUbh8jkMdCH8IJXhAXhMCk8JuNlmNyh0YiEumUwn2wMRxyHw" + "2TzWmzeb02OzGKxMITwIhnrjzbb44zRhGEKRhCM4zrr6sQKXRWH8kuXkmPj0DiXC" + "gcJbC9HZZgkKgUG4bLh3YrwJHAYw2CAh/CiN4Tq7DOZr4BB/AFtdOWW5P2h1Wkzv" + "l4+YwqXf8d5fZ7ih51QKbB4LQrLAYDBIDABA4BO4nAICApvIIfy4BeXA2DRSrQlL" + "oHHsYQ/KMXlsvl8rn8Xkcdg+G9NVaUWimUDYk9Ah/BoF4M0YBCqZPYqk8dwLf7hD" + "YNBJFLKBNqZTqNubWshl9VoM1reFYZYQEBGUsDAwKEjYuDQKBgICBgCAgIOAg4nI" + "8OACloSh/BFl4Gf/IOt6FXfF8F4ToPCZzlPwP4+B+DHmQO847rfDeCcG8eKh/EZV" + "4i9eZt8A9nUF8VzxaUe5grl7YrPaHfpRKJNx4yHmUuj1vicwmMBEAjUVgKB61A="; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - InkControl() /// <summary> /// 생성자 /// </summary> public InkControl() { this.presenter = new InkPresenter(); Content = this.presenter; StrokeCollectionConverter converter = new StrokeCollectionConverter(); if(converter.CanConvertFrom(typeof(string))) { StrokeCollection strokeCollection = converter.ConvertFrom(strokeString) as StrokeCollection; this.presenter.Strokes.Clear(); this.presenter.Strokes.Add(strokeCollection); } } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Protected #region 스타일러스 DOWN 처리하기 - OnStylusDown(e) /// <summary> /// 스타일러스 DOWN 처리하기 /// </summary> /// <param name="e">이벤트 인자</param> protected override void OnStylusDown(StylusDownEventArgs e) { base.OnStylusDown(e); StylusPointCollection pointCollection = e.GetStylusPoints(this); InitializeHitTester(pointCollection); } #endregion #region 스타일러스 이동시 처리하기 - OnStylusMove(e) /// <summary> /// 스타일러스 이동시 처리하기 /// </summary> /// <param name="e">이벤트 인자</param> protected override void OnStylusMove(StylusEventArgs e) { StylusPointCollection pointCollection = e.GetStylusPoints(this); AddPointCollectionToHitTester(pointCollection); } #endregion #region 스타일러스 UP 처리하기 - OnStylusUp(e) /// <summary> /// 스타일러스 UP 처리하기 /// </summary> /// <param name="e">이벤트 인자</param> protected override void OnStylusUp(StylusEventArgs e) { StylusPointCollection pointCollection = e.GetStylusPoints(this); StopHitTesting(pointCollection); } #endregion #region 마우스 왼쪽 버튼 DOWN 처리하기 - OnMouseLeftButtonDown(e) /// <summary> /// 마우스 왼쪽 버튼 DOWN 처리하기 /// </summary> /// <param name="e">이벤트 발생자</param> protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) { base.OnMouseLeftButtonDown(e); if(e.StylusDevice != null) { return; } Point point = e.GetPosition(this); StylusPointCollection pointCollection = new StylusPointCollection(new Point[] { point }); InitializeHitTester(pointCollection); } #endregion #region 마우스 이동시 처리하기 - OnMouseMove(e) /// <summary> /// 마우스 이동시 처리하기 /// </summary> /// <param name="e">이벤트 인자</param> protected override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); if(e.StylusDevice != null) { return; } if(e.LeftButton == MouseButtonState.Released) { return; } Point point = e.GetPosition(this); StylusPointCollection pointCollection = new StylusPointCollection(new Point[] { point }); AddPointCollectionToHitTester(pointCollection); } #endregion #region 마우스 왼쪽 버튼 UP 처리하기 - OnMouseLeftButtonUp(e) /// <summary> /// 마우스 왼쪽 버튼 UP 처리하기 /// </summary> /// <param name="e">이벤트 인자</param> protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) { base.OnMouseLeftButtonUp(e); if(e.StylusDevice != null) { return; } Point point = e.GetPosition(this); StylusPointCollection pointCollection = new StylusPointCollection(new Point[] { point }); StopHitTesting(pointCollection); } #endregion ////////////////////////////////////////////////////////////////////////////////////////// Private //////////////////////////////////////////////////////////////////////////////// Event #region 히트 테스터 스트로크 히트시 처리하기 - hitTester_StrokeHit(sender, e) /// <summary> /// 히트 테스터 스트로크 히트시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void hitTester_StrokeHit(object sender, StrokeHitEventArgs e) { StrokeCollection resultCollection = e.GetPointEraseResults(); StrokeCollection strokeCollectionToReplace = new StrokeCollection(); strokeCollectionToReplace.Add(e.HitStroke); if(resultCollection.Count > 0) { this.presenter.Strokes.Replace(strokeCollectionToReplace, resultCollection); } else { this.presenter.Strokes.Remove(strokeCollectionToReplace); } } #endregion //////////////////////////////////////////////////////////////////////////////// Function #region 히트 테스터 초기화하기 - InitializeHitTester(pointCollection) /// <summary> /// 히트 테스터 초기화하기 /// </summary> /// <param name="pointCollection">포인트 컬렉션</param> private void InitializeHitTester(StylusPointCollection pointCollection) { EllipseStylusShape shape = new EllipseStylusShape(3, 3, 0); this.hitTester = presenter.Strokes.GetIncrementalStrokeHitTester(shape); this.hitTester.StrokeHit += hitTester_StrokeHit; this.hitTester.AddPoints(pointCollection); } #endregion #region 히트 테스터에 포인트 컬렉션 추가하기 - AddPointCollectionToHitTester(pointCollection) /// <summary> /// 히트 테스터에 포인트 컬렉션 추가하기 /// </summary> /// <param name="pointCollection">포인트 컬렉션</param> private void AddPointCollectionToHitTester(StylusPointCollection pointCollection) { if(this.hitTester.IsValid) { this.hitTester.AddPoints(pointCollection); } } #endregion #region 히트 테스팅 중단하기 - StopHitTesting(pointCollection) /// <summary> /// 히트 테스팅 중단하기 /// </summary> /// <param name="pointCollection">포인트 컬렉션</param> private void StopHitTesting(StylusPointCollection pointCollection) { this.hitTester.AddPoints(pointCollection); this.hitTester.StrokeHit -= hitTester_StrokeHit; this.hitTester.EndHitTesting(); } #endregion } } |
▶ MainWindow.xaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<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="TestProject" FontFamily="나눔고딕코딩" FontSize="16"> <Border Margin="10" BorderThickness="1" BorderBrush="Black"> <local:InkControl /> </Border> </Window> |
TestProject.zip
■ InkCanvas 클래스의 Gesture 이벤트를 사용해 애플리케이션 제스처를 인식하는 방법을 보여준다. ▶ MainWindow.xaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<Window x:Class="TestProject.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="800" Height="600" Title="TestProject" FontFamily="나눔고딕코딩" FontSize="16"> <Border Margin="10" BorderThickness="1" BorderBrush="Black"> <InkCanvas Name="inkCanvas" /> </Border> </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 |
using System.Collections.ObjectModel; using System.Windows; using System.Windows.Controls; using System.Windows.Ink; namespace TestProject { /// <summary> /// 메인 윈도우 /// </summary> public partial class MainWindow : Window { //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - MainWindow() /// <summary> /// 생성자 /// </summary> public MainWindow() { InitializeComponent(); if(this.inkCanvas.IsGestureRecognizerAvailable) { this.inkCanvas.EditingMode = InkCanvasEditingMode.InkAndGesture; this.inkCanvas.Gesture += inkCanvas_Gesture; this.inkCanvas.SetEnabledGestures(new ApplicationGesture[] { ApplicationGesture.ScratchOut }); } } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Private #region 잉크 캔버스 제스처 처리하기 - inkCanvas_Gesture(sender, e) /// <summary> /// 잉크 캔버스 제스처 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void inkCanvas_Gesture(object sender, InkCanvasGestureEventArgs e) { ReadOnlyCollection<GestureRecognitionResult> resultCollection = e.GetGestureRecognitionResults(); if((resultCollection[0].RecognitionConfidence == RecognitionConfidence.Strong) && (resultCollection[0].ApplicationGesture == ApplicationGesture.ScratchOut)) { StrokeCollection hitStrokeCollection = inkCanvas.Strokes.HitTest(e.Strokes.GetBounds(), 10); if(hitStrokeCollection.Count > 0) { inkCanvas.Strokes.Remove(hitStrokeCollection); } } } #endregion } } |
TestProject.zip
■ InkCanvas 클래스의 잉크 데이터에 커스텀 데이터를 추가하는 방법을 보여준다. ▶ 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 |
<Window x:Class="TestProject.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="800" Height="600" Title="TestProject" FontFamily="나눔고딕코딩" FontSize="16"> <DockPanel> <StackPanel Background="DarkSlateBlue"> <Button Name="setPenColorButton" Margin="10 10 10 0" Padding="10" Content="청색 펜 색상 사용" /> <Button Name="changePenColorButton" Margin="10 10 10 10" Padding="10" Content="펜 색상 변경" /> </StackPanel> <Border Margin="10" BorderThickness="1" BorderBrush="Black"> <InkCanvas Name="inkCanvas" /> </Border> </DockPanel> </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 |
using System; using System.Windows; using System.Windows.Ink; using System.Windows.Media; namespace TestProject { /// <summary> /// 메인 윈도우 /// </summary> public partial class MainWindow : Window { //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region Field /// <summary> /// 펜 색상 GUID /// </summary> private Guid penColorGUID = new Guid("12345678-9012-3456-7890-123456789012"); /// <summary> /// 적색 펜 색상 드로잉 어트리뷰트 /// </summary> private DrawingAttributes redPenColorDrawingAttributes = new DrawingAttributes(); /// <summary> /// 청색 펜 색상 드로잉 어트리뷰트 /// </summary> private DrawingAttributes bluePenColorDrawingAttributes = new DrawingAttributes(); /// <summary> /// 적색 펜 색상 문자열 /// </summary> private string redPenColorString = "redPenColor"; /// <summary> /// 청색 펜 색상 문자열 /// </summary> private string bluePenColorString = "bluePenColor"; /// <summary> /// 청색 펜 색상 사용 여부 /// </summary> private bool useBluePenColor = false; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - MainWindow() /// <summary> /// 생성자 /// </summary> public MainWindow() { InitializeComponent(); this.redPenColorDrawingAttributes.Color = Colors.Red; this.redPenColorDrawingAttributes.Width = 5; this.redPenColorDrawingAttributes.Height = 5; this.redPenColorDrawingAttributes.AddPropertyData(penColorGUID, redPenColorString); this.bluePenColorDrawingAttributes.Color = Colors.Blue; this.bluePenColorDrawingAttributes.Width = 5; this.bluePenColorDrawingAttributes.Height = 5; this.bluePenColorDrawingAttributes.AddPropertyData(penColorGUID, bluePenColorString); this.inkCanvas.DefaultDrawingAttributes = this.redPenColorDrawingAttributes; this.setPenColorButton.Click += setPenColorButton_click; this.changePenColorButton.Click += changePenColorButton_click; } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Private #region 펜 색상 설정 버튼 클릭시 처리하기 - setPenColorButton_click(sender, e) /// <summary> /// 펜 색상 설정 버튼 클릭시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void setPenColorButton_click(object sender, RoutedEventArgs e) { this.useBluePenColor = !this.useBluePenColor; if(this.useBluePenColor) { this.setPenColorButton.Content = "적색 펜색 색상 사용"; this.inkCanvas.DefaultDrawingAttributes = this.bluePenColorDrawingAttributes; } else { this.setPenColorButton.Content = "청색 펜색 색상 사용"; this.inkCanvas.DefaultDrawingAttributes = this.redPenColorDrawingAttributes; } } #endregion #region 펜 색상 변경하기 버튼 클릭시 처리하기 - changePenColorButton_click(sender, e) /// <summary> /// 펜 색상 변경하기 버튼 클릭시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void changePenColorButton_click(object sender, RoutedEventArgs e) { foreach(Stroke stroke in this.inkCanvas.Strokes) { if(stroke.DrawingAttributes.ContainsPropertyData(penColorGUID)) { object data = stroke.DrawingAttributes.GetPropertyData(penColorGUID); if((data is string) && ((string)data == redPenColorString)) { stroke.DrawingAttributes.Color = Colors.Black; } if((data is string) && ((string)data == bluePenColorString)) { stroke.DrawingAttributes.Color = Colors.Green; } } } } #endregion } } |
TestProject.zip
■ UIElement 클래스를 사용해 잉크 입력 컨트롤에서 잉크를 선택하는 방법을 보여준다. ▶ InkMode.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
namespace TestProject { /// <summary> /// 잉크 모드 /// </summary> public enum InkMode { /// <summary> /// 잉크 /// </summary> Ink, /// <summary> /// 선택 /// </summary> Select } } |
▶ InkControl.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 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 |
using System; using System.Windows; using System.Windows.Controls; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Input.StylusPlugIns; using System.Windows.Media; namespace TestProject { /// <summary> /// 잉크 컨트롤 /// </summary> public class InkControl : Label { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 잉크 모드 /// </summary> private InkMode mode; /// <summary> /// 잉크 드로잉 어트리뷰트 /// </summary> private DrawingAttributes inkDrawingAttributes; /// <summary> /// 선택 드로잉 어트리뷰트 /// </summary> private DrawingAttributes selectionDrawingAttributes; /// <summary> /// 잉크 프리젠터 /// </summary> private InkPresenter presenter; /// <summary> /// 선택 증분 올가미 히트 테스터 /// </summary> private IncrementalLassoHitTester selectionIncrementalLassoHitTester; /// <summary> /// 선택 스트로크 컬렉션 /// </summary> private StrokeCollection selectedStrokeCollection = new StrokeCollection(); /// <summary> /// 스타일러스 포인트 컬렉션 /// </summary> private StylusPointCollection stylusPointCollection; /// <summary> /// 올가미 경로 스트로크 /// </summary> private Stroke lassoPathStroke; /// <summary> /// 동적 렌더러 /// </summary> private DynamicRenderer renderer; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 모드 - Mode /// <summary> /// 모드 /// </summary> public InkMode Mode { get { return this.mode; } set { this.mode = value; if(this.mode == InkMode.Ink) { this.renderer.DrawingAttributes = this.inkDrawingAttributes; } else { this.renderer.DrawingAttributes = this.selectionDrawingAttributes; } this.presenter.DetachVisuals(this.renderer.RootVisual); this.presenter.AttachVisuals(this.renderer.RootVisual, this.renderer.DrawingAttributes); } } #endregion #region 잉크 드로잉 어트리뷰트 - InkDrawingAttributes /// <summary> /// 잉크 드로잉 어트리뷰트 /// </summary> public DrawingAttributes InkDrawingAttributes { get { return this.inkDrawingAttributes; } } #endregion #region 선택 드로잉 어트리뷰트 - SelectionDrawingAttributes /// <summary> /// 선택 드로잉 어트리뷰트 /// </summary> public DrawingAttributes SelectionDrawingAttributes { get { return this.selectionDrawingAttributes; } } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Static #region 생성자 - InkControl() /// <summary> /// 생성자 /// </summary> static InkControl() { Type ownerType = typeof(InkControl); ClipToBoundsProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(true)); } #endregion ////////////////////////////////////////////////////////////////////////////////////////// Instance //////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - InkControl() /// <summary> /// 생성자 /// </summary> public InkControl() { this.mode = InkMode.Ink; this.presenter = new InkPresenter(); Content = this.presenter; this.inkDrawingAttributes = new DrawingAttributes(); this.inkDrawingAttributes.Width = 5; this.inkDrawingAttributes.Height = 5; this.selectionDrawingAttributes = new DrawingAttributes(); this.selectionDrawingAttributes.Color = Colors.DarkGray; this.selectionDrawingAttributes.Width = 3; this.selectionDrawingAttributes.Height = 3; this.inkDrawingAttributes.AttributeChanged += new PropertyDataChangedEventHandler(drawingAttributes_AttributeChanged); this.selectionDrawingAttributes.AttributeChanged += new PropertyDataChangedEventHandler(drawingAttributes_AttributeChanged); this.renderer = new DynamicRenderer(); this.renderer.DrawingAttributes = this.inkDrawingAttributes; StylusPlugIns.Add(this.renderer); this.presenter.AttachVisuals(this.renderer.RootVisual, this.renderer.DrawingAttributes); } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Protected #region 스타일러스 DOWN 처리하기 - OnStylusDown(e) /// <summary> /// 스타일러스 DOWN 처리하기 /// </summary> /// <param name="e">이벤트 인자</param> protected override void OnStylusDown(StylusDownEventArgs e) { base.OnStylusDown(e); Stylus.Capture(this); this.stylusPointCollection = new StylusPointCollection(); StylusPointCollection pointCollection = e.GetStylusPoints(this, this.stylusPointCollection.Description); this.stylusPointCollection.Add(pointCollection); InitializeHitTester(pointCollection); } #endregion #region 스타일러스 이동시 처리하기 - OnStylusMove(e) /// <summary> /// 스타일러스 이동시 처리하기 /// </summary> /// <param name="e">이벤트 인자</param> protected override void OnStylusMove(StylusEventArgs e) { if(this.stylusPointCollection == null) { return; } StylusPointCollection pointCollection = e.GetStylusPoints(this, this.stylusPointCollection.Description); this.stylusPointCollection.Add(pointCollection); AddPointsToHitTester(pointCollection); } #endregion #region 스타일러스 UP 처리하기 - OnStylusUp(e) /// <summary> /// 스타일러스 UP 처리하기 /// </summary> /// <param name="e">이벤트 발생자</param> protected override void OnStylusUp(StylusEventArgs e) { this.stylusPointCollection = this.stylusPointCollection ?? new StylusPointCollection(); StylusPointCollection pointCollection = e.GetStylusPoints(this, this.stylusPointCollection.Description); this.stylusPointCollection.Add(pointCollection); AddPointsToHitTester(pointCollection); AddStrokeToPresenter(Mode == InkMode.Select); this.stylusPointCollection = null; Stylus.Capture(null); } #endregion #region 마우스 왼쪽 버튼 DOWN 처리하기 - OnMouseLeftButtonDown(e) /// <summary> /// 마우스 왼쪽 버튼 DOWN 처리하기 /// </summary> /// <param name="e">이벤트 인자</param> protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) { base.OnMouseLeftButtonDown(e); Mouse.Capture(this); if(e.StylusDevice != null) { return; } Point point = e.GetPosition(this); StylusPointCollection pointCollection = new StylusPointCollection(new Point[] { point }); this.stylusPointCollection = new StylusPointCollection(); this.stylusPointCollection.Add(pointCollection); InitializeHitTester(pointCollection); } #endregion #region 마우스 이동시 처리하기 - OnMouseMove(e) /// <summary> /// 마우스 이동시 처리하기 /// </summary> /// <param name="e">이벤트 인자</param> protected override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); if(e.StylusDevice != null) { return; } if(e.LeftButton == MouseButtonState.Released) { return; } this.stylusPointCollection = this.stylusPointCollection ?? new StylusPointCollection(); Point point = e.GetPosition(this); StylusPointCollection pointCollection = new StylusPointCollection(new Point[] { point }); this.stylusPointCollection.Add(pointCollection); AddPointsToHitTester(pointCollection); } #endregion #region 마우스 왼쪽 버튼 UP 처리하기 - OnMouseLeftButtonUp(e) /// <summary> /// 마우스 왼쪽 버튼 UP 처리하기 /// </summary> /// <param name="e">이벤트 인자</param> protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) { base.OnMouseLeftButtonUp(e); if(e.StylusDevice != null) { return; } if(this.stylusPointCollection == null) { this.stylusPointCollection = new StylusPointCollection(); } Point point = e.GetPosition(this); StylusPointCollection pointCollection = new StylusPointCollection(new Point[] { point }); this.stylusPointCollection.Add(pointCollection); AddPointsToHitTester(pointCollection); AddStrokeToPresenter(Mode == InkMode.Select); this.stylusPointCollection = null; Mouse.Capture(null); } #endregion ////////////////////////////////////////////////////////////////////////////////////////// Private //////////////////////////////////////////////////////////////////////////////// Event #region 드로잉 어트리뷰트 어트리뷰트 변경시 처리하기 - drawingAttributes_AttributeChanged(sender, e) /// <summary> /// 드로잉 어트리뷰트 어트리뷰트 변경시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void drawingAttributes_AttributeChanged(object sender, PropertyDataChangedEventArgs e) { this.presenter.DetachVisuals(this.renderer.RootVisual); this.presenter.AttachVisuals(this.renderer.RootVisual, this.renderer.DrawingAttributes); } #endregion #region 선택 증분 올가미 히트 테스터 선택 변경시 처리하기 - selectionIncrementalLassoHitTester_SelectionChanged(sender, e) /// <summary> /// 선택 증분 올가미 히트 테스터 선택 변경시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void selectionIncrementalLassoHitTester_SelectionChanged(object sender, LassoSelectionChangedEventArgs e) { foreach(Stroke selectedStroke in e.SelectedStrokes) { selectedStroke.DrawingAttributes.Color = Colors.Red; this.selectedStrokeCollection.Add(selectedStroke); } foreach(Stroke unselectedStroke in e.DeselectedStrokes) { unselectedStroke.DrawingAttributes.Color = this.inkDrawingAttributes.Color; this.selectedStrokeCollection.Remove(unselectedStroke); } } #endregion //////////////////////////////////////////////////////////////////////////////// Function #region 히트 테스터 초기화하기 - InitializeHitTester(pointCollection) /// <summary> /// 히트 테스터 초기화하기 /// </summary> /// <param name="pointCollection">포인트 컬렉션</param> private void InitializeHitTester(StylusPointCollection pointCollection) { foreach(Stroke selectedStroke in this.selectedStrokeCollection) { selectedStroke.DrawingAttributes.Color = this.inkDrawingAttributes.Color; } this.selectedStrokeCollection.Clear(); if(this.mode == InkMode.Select) { if(this.lassoPathStroke != null) { this.presenter.Strokes.Remove(this.lassoPathStroke); this.lassoPathStroke = null; } this.selectionIncrementalLassoHitTester = this.presenter.Strokes.GetIncrementalLassoHitTester(80); this.selectionIncrementalLassoHitTester.SelectionChanged += selectionIncrementalLassoHitTester_SelectionChanged; this.selectionIncrementalLassoHitTester.AddPoints(pointCollection); } } #endregion #region 히트 테스트에 포인트 추가하기 - AddPointsToHitTester(pointCollection) /// <summary> /// 히트 테스트에 포인트 추가하기 /// </summary> /// <param name="pointCollection">포인트 컬렉션</param> private void AddPointsToHitTester(StylusPointCollection pointCollection) { if(this.mode == InkMode.Select && this.selectionIncrementalLassoHitTester != null && this.selectionIncrementalLassoHitTester.IsValid) { this.selectionIncrementalLassoHitTester.AddPoints(pointCollection); } } #endregion #region 프리젠터에 스트로크 추가하기 - AddStrokeToPresenter() /// <summary> /// 프리젠터에 스트로크 추가하기 /// </summary> private void AddStrokeToPresenter(bool up = false) { Stroke newStroke = new Stroke(this.stylusPointCollection); if(this.mode == InkMode.Ink) { newStroke.DrawingAttributes = this.inkDrawingAttributes.Clone(); this.presenter.Strokes.Add(newStroke); } if(this.mode == InkMode.Select && this.lassoPathStroke == null) { if(up) { this.presenter.Strokes.Remove(this.lassoPathStroke); } else { this.lassoPathStroke = newStroke; this.lassoPathStroke.DrawingAttributes = this.selectionDrawingAttributes.Clone(); this.presenter.Strokes.Add(this.lassoPathStroke); this.selectionIncrementalLassoHitTester.SelectionChanged -= selectionIncrementalLassoHitTester_SelectionChanged; this.selectionIncrementalLassoHitTester.EndHitTesting(); } } } #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 |
<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="TestProject" FontFamily="나눔고딕코딩" FontSize="16"> <Grid> <local:InkControl x:Name="inkControl" /> <StackPanel HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10" Orientation="Vertical"> <Button Name="inkButton" HorizontalAlignment="Left" Width="100" Height="30" Content="잉크" /> <Button Name="selectButton" HorizontalAlignment="Left" Margin="0 10 0 0" Width="100" Height="30" Content="선택하기" /> </StackPanel> </Grid> </Window> |
▶ MainWindow.xaml.cs
■ UIElement 클래스에서 잉크 입력 컨트롤을 만드는 방법을 보여준다. ▶ InkControl.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 |
using System; using System.Windows; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Input.StylusPlugIns; using System.Windows.Controls; namespace TestProject { /// <summary> /// 잉크 컨트롤 /// </summary> public class InkControl : Label { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 잉크 프리젠터 /// </summary> private InkPresenter presenter; /// <summary> /// 동적 렌더러 /// </summary> private DynamicRenderer renderer; /// <summary> /// 스타일러스 포인트 컬렉션 /// </summary> private StylusPointCollection pointCollection = null; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Static #region 생성자 - InkControl() /// <summary> /// 생성자 /// </summary> static InkControl() { Type ownerType = typeof(InkControl); ClipToBoundsProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(true)); } #endregion ////////////////////////////////////////////////////////////////////////////////////////// Instance //////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - InkControl() /// <summary> /// 생성자 /// </summary> public InkControl() { this.presenter = new InkPresenter(); Content = this.presenter; this.renderer = new DynamicRenderer(); this.presenter.AttachVisuals(this.renderer.RootVisual, this.renderer.DrawingAttributes); StylusPlugIns.Add(this.renderer); } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Public #region 스타일러스 DOWN 처리하기 - OnStylusDown(e) /// <summary> /// 스타일러스 DOWN 처리하기 /// </summary> /// <param name="e">이벤트 발생자</param> protected override void OnStylusDown(StylusDownEventArgs e) { Stylus.Capture(this); this.pointCollection = new StylusPointCollection(); StylusPointCollection pointCollection = e.GetStylusPoints(this, this.pointCollection.Description); this.pointCollection.Add(pointCollection); } #endregion #region 스타일러스 이동시 처리하기 - OnStylusMove(e) /// <summary> /// 스타일러스 이동시 처리하기 /// </summary> /// <param name="e">이벤트 인자</param> protected override void OnStylusMove(StylusEventArgs e) { if(this.pointCollection == null) { return; } StylusPointCollection pointCollection = e.GetStylusPoints(this, this.pointCollection.Description); this.pointCollection.Add(pointCollection); } #endregion #region 스타일러스 UP 처리하기 - OnStylusUp(e) /// <summary> /// 스타일러스 UP 처리하기 /// </summary> /// <param name="e">이벤트 인자</param> protected override void OnStylusUp(StylusEventArgs e) { if(this.pointCollection == null) { return; } StylusPointCollection pointCollection = e.GetStylusPoints(this, this.pointCollection.Description); this.pointCollection.Add(pointCollection); Stroke stroke = new Stroke(this.pointCollection); this.presenter.Strokes.Add(stroke); this.pointCollection = null; Stylus.Capture(null); } #endregion #region 마우슨 왼쪽 버튼 DOWN 처리하기 - OnMouseLeftButtonDown(e) /// <summary> /// 마우슨 왼쪽 버튼 DOWN 처리하기 /// </summary> /// <param name="e">이벤트 인자</param> protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) { base.OnMouseLeftButtonDown(e); if(e.StylusDevice != null) { return; } this.pointCollection = new StylusPointCollection(); Point point = e.GetPosition(this); this.pointCollection.Add(new StylusPoint(point.X, point.Y)); } #endregion #region 마우스 이동시 처리하기 - OnMouseMove(e) /// <summary> /// 마우스 이동시 처리하기 /// </summary> /// <param name="e">이벤트 발생자</param> protected override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); if(e.StylusDevice != null) { return; } if(e.LeftButton == MouseButtonState.Released || this.pointCollection == null) { return; } Point point = e.GetPosition(this); this.pointCollection.Add(new StylusPoint(point.X, point.Y)); } #endregion #region 마우스 왼쪽 버튼 UP 처리하기 - OnMouseLeftButtonUp(e) /// <summary> /// 마우스 왼쪽 버튼 UP 처리하기 /// </summary> /// <param name="e">이벤트 인자</param> protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) { base.OnMouseLeftButtonUp(e); if(e.StylusDevice != null) { return; } if(this.pointCollection == null) { return; } Point point = e.GetPosition(this); this.pointCollection.Add(new StylusPoint(point.X, point.Y)); Stroke stroke = new Stroke(this.pointCollection); stroke.DrawingAttributes = this.renderer.DrawingAttributes; this.presenter.Strokes.Add(stroke); this.pointCollection = null; } #endregion } } |
▶ MainWindow.xaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<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="TestProject" FontFamily="나눔고딕코딩" FontSize="16"> <Border Margin="10" BorderThickness="2" BorderBrush="Black"> <local:InkControl /> </Border> </Window> |
TestProject.zip
■ InkCanvas 클래스의 StylusPlugIns 속성을 사용해 커스텀 스타일러스 플러그인을 설정하는 방법을 보여준다. ▶ CustomStylusPlugIn.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 |
using System.Windows.Input; using System.Windows.Input.StylusPlugIns; namespace TestProject { /// <summary> /// 커스텀 스타일러스 플러그인 /// </summary> public class CustomStylusPlugIn : StylusPlugIn { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Protected #region 스타일러스 DOWN 처리하기 - OnStylusDown(rawStylusInput) /// <summary> /// 스타일러스 DOWN 처리하기 /// </summary> /// <param name="rawStylusInput">원시 스타일러스 입력</param> protected override void OnStylusDown(RawStylusInput rawStylusInput) { base.OnStylusDown(rawStylusInput); Filter(rawStylusInput); } #endregion #region 스타일러스 이동시 처리하기 - OnStylusMove(rawStylusInput) /// <summary> /// 스타일러스 이동시 처리하기 /// </summary> /// <param name="rawStylusInput">원시 스타일러스 입력</param> protected override void OnStylusMove(RawStylusInput rawStylusInput) { base.OnStylusMove(rawStylusInput); Filter(rawStylusInput); } #endregion #region 스타일러스 UP 처리하기 - OnStylusUp(rawStylusInput) /// <summary> /// 스타일러스 UP 처리하기 /// </summary> /// <param name="rawStylusInput">원시 스타일러스 입력</param> protected override void OnStylusUp(RawStylusInput rawStylusInput) { base.OnStylusUp(rawStylusInput); Filter(rawStylusInput); } #endregion ////////////////////////////////////////////////////////////////////////////////////////// Private #region 필터링하기 - Filter(rawStylusInput) /// <summary> /// 필터링하기 /// </summary> /// <param name="rawStylusInput">원시 스타일러스 입력</param> private void Filter(RawStylusInput rawStylusInput) { StylusPointCollection collection = rawStylusInput.GetStylusPoints(); for(int i = 0; i < collection.Count; i++) { StylusPoint point = collection[i]; if(point.X < 50 ) point.X = 50; if(point.X > 250) point.X = 250; if(point.Y < 50 ) point.Y = 50; if(point.Y > 250) point.Y = 250; collection[i] = point; } rawStylusInput.SetStylusPoints(collection); } #endregion } } |
▶ CustomInkCanvas.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 |
using System.Windows.Controls; namespace TestProject { /// <summary> /// 커스텀 잉크 캔버스 /// </summary> public class CustomInkCanvas : InkCanvas { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 커스텀 스타일러스 플러그 인 /// </summary> private CustomStylusPlugIn plugIn = new CustomStylusPlugIn(); #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - CustomInkCanvas() /// <summary> /// 생성자 /// </summary> public CustomInkCanvas() : base() { int dynamicRenderIndex = StylusPlugIns.IndexOf(DynamicRenderer); StylusPlugIns.Insert(dynamicRenderIndex, this.plugIn); } #endregion } } |
▶ MainWindow.xaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<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="TestProject" FontFamily="나눔고딕코딩" FontSize="16"> <Border Margin="10" BorderThickness="2" BorderBrush="Black"> <local:CustomInkCanvas /> </Border> </Window> |
TestProject.zip
■ InkCanvas 클래스에서 커스텀 렌더링 잉크를 사용하는 방법을 보여준다. ▶ CustomStroke.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 |
using System.Windows; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Media; namespace TestProject { /// <summary> /// 커스텀 스트로크 /// </summary> public class CustomStroke : Stroke { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 브러시 /// </summary> private Brush brush; /// <summary> /// 펜 /// </summary> private Pen pen; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - CustomStroke(stylusPointCollection) /// <summary> /// 생성자 /// </summary> /// <param name="stylusPointCollection">스타일러스 포인트 컬렉션</param> public CustomStroke(StylusPointCollection stylusPointCollection) : base(stylusPointCollection) { this.brush = new LinearGradientBrush(Colors.Red, Colors.Blue, 20d); this.pen = new Pen(this.brush, 2d); } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Protected #region 그리기 (코어) - DrawCore(drawingContext, drawingAttributes) /// <summary> /// 그리기 (코어) /// </summary> /// <param name="drawingContext">드로잉 컨텍스트</param> /// <param name="drawingAttributes">드로잉 어트리뷰트</param> protected override void DrawCore(DrawingContext drawingContext, DrawingAttributes drawingAttributes) { Point previousPoint = new Point(double.NegativeInfinity, double.NegativeInfinity); for(int i = 0; i < StylusPoints.Count; i++) { Point point = (Point)StylusPoints[i]; Vector vector = Point.Subtract(previousPoint, point); if(vector.Length > 4) { double radius = StylusPoints[i].PressureFactor * 10d; drawingContext.DrawEllipse(this.brush, this.pen, point, radius, radius); previousPoint = point; } } } #endregion } } |
▶ CustomDynamicRenderer.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 |
using System; using System.Windows; using System.Windows.Input; using System.Windows.Input.StylusPlugIns; using System.Windows.Media; namespace TestProject { /// <summary> /// 커스텀 동적 렌더러 /// </summary> public class CustomDynamicRenderer : DynamicRenderer { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 브러시 /// </summary> [ThreadStatic] private static Brush _brush = null; /// <summary> /// 펜 /// </summary> [ThreadStatic] private static Pen _pen = null; #endregion ////////////////////////////////////////////////////////////////////////////////////////// Instance //////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 이전 포인트 /// </summary> private Point previousPoint; #endregion ////////////////////////////////////////////////////////////////////////////////////////// Method //////////////////////////////////////////////////////////////////////////////// Protected #region 스타일러스 DOWN 처리하기 - OnStylusDown(rawStylusInput) /// <summary> /// 스타일러스 DOWN 처리하기 /// </summary> /// <param name="rawStylusInput">원시 스타일러스 입력</param> protected override void OnStylusDown(RawStylusInput rawStylusInput) { this.previousPoint = new Point(double.NegativeInfinity, double.NegativeInfinity); base.OnStylusDown(rawStylusInput); } #endregion #region 그리기 처리하기 - OnDraw(drawingContext, stylusPointCollection, geometry, fillBrush) /// <summary> /// 그리기 처리하기 /// </summary> /// <param name="drawingContext">드로잉 컨텍스트</param> /// <param name="stylusPointCollection">스타일러스 포인트 컬렉션</param> /// <param name="geometry">지오메트리</param> /// <param name="fillBrush">채우기 브러시</param> protected override void OnDraw(DrawingContext drawingContext, StylusPointCollection stylusPointCollection, Geometry geometry, Brush fillBrush) { _brush = _brush ?? new LinearGradientBrush(Colors.Red, Colors.Blue, 20d); _pen = _pen ?? new Pen(_brush, 2d); for(int i = 0; i < stylusPointCollection.Count; i++) { Point point = (Point)stylusPointCollection[i]; Vector vector = Point.Subtract(this.previousPoint, point); if(vector.Length > 4) { double radius = stylusPointCollection[i].PressureFactor * 10d; drawingContext.DrawEllipse(_brush, _pen, point, radius, radius); this.previousPoint = point; } } } #endregion } } |
▶ CustomInkCanvas.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 |
using System.Windows.Controls; namespace TestProject { /// <summary> /// 커스텀 잉크 캔버스 /// </summary> public class CustomInkCanvas : InkCanvas { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 커스텀 동적 렌더러 /// </summary> private CustomDynamicRenderer renderer = new CustomDynamicRenderer(); #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - CustomInkCanvas() /// <summary> /// 생성자 /// </summary> public CustomInkCanvas() : base() { DynamicRenderer = this.renderer; } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Protected #region 스트로크 수집시 처리하기 - OnStrokeCollected(e) /// <summary> /// 스트로크 수집시 처리하기 /// </summary> /// <param name="e">이벤트 인자</param> protected override void OnStrokeCollected(InkCanvasStrokeCollectedEventArgs e) { Strokes.Remove(e.Stroke); CustomStroke stroke = new CustomStroke(e.Stroke.StylusPoints); Strokes.Add(stroke); InkCanvasStrokeCollectedEventArgs inkCanvasStrokeCollectedEventArgs = new InkCanvasStrokeCollectedEventArgs(stroke); base.OnStrokeCollected(inkCanvasStrokeCollectedEventArgs); } #endregion } } |
▶ MainWindow.xaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<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="TestProject" FontFamily="나눔고딕코딩" FontSize="16"> <Border Margin="10" BorderThickness="2" BorderBrush="Black"> <local:CustomInkCanvas /> </Border> </Window> |
TestProject.zip
■ InkCanvas 클래스에서 ISF(Ink Serialized Format) 파일을 로드하고 저장하는 방법을 보여준다. ▶ 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 |
<Window x:Class="TestProject.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="800" Height="600" Title="TestProject" FontFamily="나눔고딕코딩" FontSize="16"> <Grid Margin="10"> <Grid.RowDefinitions> <RowDefinition Height="*" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <Border Grid.Row="0" BorderThickness="2" BorderBrush="Black"> <InkCanvas Name="inkCanvas" /> </Border> <StackPanel Grid.Row="1" HorizontalAlignment="Center" Margin="10" Orientation="Horizontal"> <Button Name="loadButton" Width="100" Height="30" Content="로드하기" /> <Button Name="saveButton" Margin="10 0 0 0" Width="100" Height="30" Content="저장하기" /> <Button Name="clearButton" Margin="10 0 0 0" Width="100" Height="30" Content="지우기" /> </StackPanel> </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 |
using System.IO; using System.Windows; using System.Windows.Ink; using Microsoft.Win32; namespace TestProject { /// <summary> /// 메인 윈도우 /// </summary> public partial class MainWindow : Window { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 파일 열기 대화 상자 /// </summary> private OpenFileDialog openFileDialog; /// <summary> /// 파일 저장하기 대화 상자 /// </summary> private SaveFileDialog saveFileDialog; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - MainWindow() /// <summary> /// 생성자 /// </summary> public MainWindow() { InitializeComponent(); this.openFileDialog = new OpenFileDialog(); this.openFileDialog.Filter = "isf 파일 (*.isf)|*.isf"; this.saveFileDialog = new SaveFileDialog(); this.saveFileDialog.Filter = "isf 파일 (*.isf)|*.isf"; this.loadButton.Click += loadButton_Click; this.saveButton.Click += saveButton_Click; this.clearButton.Click += clearButton_Click; } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Private #region 로드하기 버튼 클릭시 처리하기 - loadButton_Click(sender, e) /// <summary> /// 로드하기 버튼 클릭시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void loadButton_Click(object sender, RoutedEventArgs e) { if(this.openFileDialog.ShowDialog() == true) { using(FileStream fileStream = new FileStream(this.openFileDialog.FileName, FileMode.Open)) { this.inkCanvas.Strokes = new StrokeCollection(fileStream); } } } #endregion #region 저장하기 버튼 클릭시 처리하기 - saveButton_Click(sender, e) /// <summary> /// 저장하기 버튼 클릭시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void saveButton_Click(object sender, RoutedEventArgs e) { if(this.saveFileDialog.ShowDialog() == true) { using(FileStream fileStream = new FileStream(this.saveFileDialog.FileName, FileMode.Create)) { this.inkCanvas.Strokes.Save(fileStream); } } } #endregion #region 지우기 버튼 클릭시 처리하기 - clearButton_Click(sender, e) /// <summary> /// 지우기 버튼 클릭시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void clearButton_Click(object sender, RoutedEventArgs e) { this.inkCanvas.Strokes.Clear(); } #endregion } } |
TestProject.zip
■ InkCanvas 클래스에서 필기를 인식하는 방법을 보여준다. ▶ 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 |
<Window x:Class="TestProject.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="800" Height="600" Title="TestProject" FontFamily="나눔고딕코딩" FontSize="16"> <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center"> <Border Width="300" Height="300" BorderThickness="2" BorderBrush="Black" Background="White"> <InkCanvas Name="inkCanvas" /> </Border> <StackPanel HorizontalAlignment="Center" Margin="10" Orientation="Horizontal"> <TextBox Name="resultTextBox" Width="225" Height="25" BorderThickness="1" BorderBrush="Black" IsReadOnly="True" VerticalContentAlignment="Center" /> <Button Name="recognizeButton" Margin="10 0 0 0" Width="100" Height="30" Content="인식하기" /> </StackPanel> <Button x:Name="clearCanvasButton" Width="150" Height="30" Content="캐버스 지우기" /> </StackPanel> </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 |
using System.IO; using System.Windows; using Microsoft.Ink; namespace TestProject { /// <summary> /// 메인 윈도우 /// </summary> public partial class MainWindow : Window { //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - MainWindow() /// <summary> /// 생성자 /// </summary> public MainWindow() { InitializeComponent(); this.recognizeButton.Click += recognizeButton_Click; this.clearCanvasButton.Click += clearCanvasButton_Click; } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Private #region 인식하기 버튼 클릭시 처리하기 - recognizeButton_Click(sender, e) /// <summary> /// 인식하기 버튼 클릭시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void recognizeButton_Click(object sender, RoutedEventArgs e) { using(MemoryStream stream = new MemoryStream()) { this.inkCanvas.Strokes.Save(stream); Ink ink = new Ink(); ink.Load(stream.ToArray()); using(RecognizerContext context = new RecognizerContext()) { if(ink.Strokes.Count > 0) { context.Strokes = ink.Strokes; RecognitionStatus status; RecognitionResult result = context.Recognize(out status); if(status == RecognitionStatus.NoError) { this.resultTextBox.Text = result.TopString; } else { MessageBox.Show("글자 인식을 실패했습니다."); } } else { MessageBox.Show("글자 획을 발견할 수 없습니다."); } } } } #endregion #region 캔버스 지우기 버튼 클릭시 처리하기 - clearCanvasButton_Click(sender, e) /// <summary> /// 캔버스 지우기 버튼 클릭시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void clearCanvasButton_Click(object sender, RoutedEventArgs e) { this.inkCanvas.Strokes.Clear(); this.resultTextBox.Text = null; } #endregion } } |
※ C:\Program Files\Common Files\microsoft shared\ink\Microsoft.Ink.dll 파일을 참조한다. TestProject.zip
■ InkCanvas 클래스의 GetSelectedStrokes 메소드를 사용해 선택 스트로크 색상을 변경하는 방법을 보여준다. ▶ 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 48 49 50 51 52 53 54 55 56 57 |
<Window x:Class="TestProject.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ink="clr-namespace:System.Windows.Ink;assembly=PresentationCore" Width="800" Height="600" Title="TestProject" FontFamily="나눔고딕코딩" FontSize="16"> <Grid> <InkCanvas Name="inkCanvas" Background="Ivory"> <InkCanvas.DefaultDrawingAttributes> <ink:DrawingAttributes Color="Red" Width="5" /> </InkCanvas.DefaultDrawingAttributes> </InkCanvas> <StackPanel HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10" Orientation="Vertical"> <Button Name="inkButton" HorizontalAlignment="Left" Width="100" Height="30" Content="잉크" /> <Button Name="highlightButton" HorizontalAlignment="Left" Margin="0 10 0 0" Width="120" Height="30" Content="하이라이트" /> <Button Name="eraseStrokeButton" HorizontalAlignment="Left" Margin="0 10 0 0" Width="150" Height="30" Content="스트로크 지우기" /> <Button Name="selectButton" HorizontalAlignment="Left" Margin="0 10 0 0" Width="100" Height="30" Content="선택하기" /> <Button Name="changeColorButton" HorizontalAlignment="Left" Margin="0 10 0 0" Width="200" Height="30" Content="선택 스트로크 색상 변경" /> </StackPanel> </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 |
using System.Windows; using System.Windows.Controls; using System.Windows.Ink; using System.Windows.Media; namespace TestProject { /// <summary> /// 메인 윈도우 /// </summary> public partial class MainWindow : Window { //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - MainWindow() /// <summary> /// 생성자 /// </summary> public MainWindow() { InitializeComponent(); this.inkButton.Click += inkButton_Click; this.highlightButton.Click += highlightButton_Click; this.selectButton.Click += selectButton_Click; this.eraseStrokeButton.Click += eraseStrokeButton_Click; this.changeColorButton.Click += changeColorButton_Click; } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Private #region 잉크 버튼 클릭시 처리하기 - inkButton_Click(sender, e) /// <summary> /// 잉크 버튼 클릭시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void inkButton_Click(object sender, RoutedEventArgs e) { this.inkCanvas.EditingMode = InkCanvasEditingMode.Ink; this.inkCanvas.DefaultDrawingAttributes.Height = 2; this.inkCanvas.DefaultDrawingAttributes.Color = Colors.Red; this.inkCanvas.DefaultDrawingAttributes.IsHighlighter = false; } #endregion #region 하이라이트 버튼 클릭시 처리하기 - highlightButton_Click(sender, e) /// <summary> /// 하이라이트 버튼 클릭시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void highlightButton_Click(object sender, RoutedEventArgs e) { this.inkCanvas.EditingMode = InkCanvasEditingMode.Ink; this.inkCanvas.DefaultDrawingAttributes.Height = 25; this.inkCanvas.DefaultDrawingAttributes.Color = Colors.Yellow; this.inkCanvas.DefaultDrawingAttributes.IsHighlighter = true; } #endregion #region 스트로크 지우기 버튼 클릭시 처리하기 - eraseStrokeButton_Click(sender, e) /// <summary> /// 스트로크 지우기 버튼 클릭시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void eraseStrokeButton_Click(object sender, RoutedEventArgs e) { this.inkCanvas.EditingMode = InkCanvasEditingMode.EraseByStroke; } #endregion #region 선택하기 버튼 클릭시 처리하기 - selectButton_Click(sender, e) /// <summary> /// 선택하기 버튼 클릭시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void selectButton_Click(object sender, RoutedEventArgs e) { this.inkCanvas.EditingMode = InkCanvasEditingMode.Select; } #endregion #region 선택 스트로크 색상 변경 버튼 클릭시 처리하기 - changeColorButton_Click(sender, e) /// <summary> /// 선택 스트로크 색상 변경 버튼 클릭시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void changeColorButton_Click(object sender, RoutedEventArgs e) { StrokeCollection strokeCollection = this.inkCanvas.GetSelectedStrokes(); if(strokeCollection.Count > 0) { foreach(Stroke stroke in strokeCollection) { stroke.DrawingAttributes.Color = Colors.Blue; } } } #endregion } } |
TestProject.zip
■ InkCanvas 클래스의 DefaultDrawingAttributes 속성을 사용해 스트로크 모양을 설정하는 방법을 보여준다. ▶ 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 48 49 50 51 |
<Window x:Class="TestProject.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ink="clr-namespace:System.Windows.Ink;assembly=PresentationCore" Width="800" Height="600" Title="TestProject" FontFamily="나눔고딕코딩" FontSize="16"> <Grid> <InkCanvas Name="inkCanvas" Background="Ivory"> <InkCanvas.DefaultDrawingAttributes> <ink:DrawingAttributes Color="Red" Width="5" /> </InkCanvas.DefaultDrawingAttributes> </InkCanvas> <StackPanel HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10" Orientation="Vertical"> <Button Name="inkButton" HorizontalAlignment="Left" Width="100" Height="30" Content="잉크" /> <Button Name="highlightButton" HorizontalAlignment="Left" Margin="0 10 0 0" Width="120" Height="30" Content="하이라이트" /> <Button Name="eraseStrokeButton" HorizontalAlignment="Left" Margin="0 10 0 0" Width="150" Height="30" Content="스트로크 지우기" /> <Button Name="selectButton" HorizontalAlignment="Left" Margin="0 10 0 0" Width="100" Height="30" Content="선택하기" /> </StackPanel> </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 |
using System.Windows; using System.Windows.Controls; using System.Windows.Media; namespace TestProject { /// <summary> /// 메인 윈도우 /// </summary> public partial class MainWindow : Window { //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - MainWindow() /// <summary> /// 생성자 /// </summary> public MainWindow() { InitializeComponent(); this.inkButton.Click += inkButton_Click; this.highlightButton.Click += highlightButton_Click; this.eraseStrokeButton.Click += eraseStrokeButton_Click; this.selectButton.Click += selectButton_Click; } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Private #region 잉크 버튼 클릭시 처리하기 - inkButton_Click(sender, e) /// <summary> /// 잉크 버튼 클릭시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void inkButton_Click(object sender, RoutedEventArgs e) { this.inkCanvas.EditingMode = InkCanvasEditingMode.Ink; this.inkCanvas.DefaultDrawingAttributes.Height = 2; this.inkCanvas.DefaultDrawingAttributes.Color = Colors.Red; this.inkCanvas.DefaultDrawingAttributes.IsHighlighter = false; } #endregion #region 하이라이트 버튼 클릭시 처리하기 - highlightButton_Click(sender, e) /// <summary> /// 하이라이트 버튼 클릭시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void highlightButton_Click(object sender, RoutedEventArgs e) { this.inkCanvas.EditingMode = InkCanvasEditingMode.Ink; this.inkCanvas.DefaultDrawingAttributes.Height = 25; this.inkCanvas.DefaultDrawingAttributes.Color = Colors.Yellow; this.inkCanvas.DefaultDrawingAttributes.IsHighlighter = true; } #endregion #region 스트로크 지우기 버튼 클릭시 처리하기 - eraseStrokeButton_Click(sender, e) /// <summary> /// 스트로크 지우기 버튼 클릭시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void eraseStrokeButton_Click(object sender, RoutedEventArgs e) { this.inkCanvas.EditingMode = InkCanvasEditingMode.EraseByStroke; } #endregion #region 선택하기 버튼 클릭시 처리하기 - selectButton_Click(sender, e) /// <summary> /// 선택하기 버튼 클릭시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void selectButton_Click(object sender, RoutedEventArgs e) { this.inkCanvas.EditingMode = InkCanvasEditingMode.Select; } #endregion } } |
TestProject.zip
■ InkCanvas 클래스의 MouseRightButtonUp 이벤트를 사용해 스트로크 크기를 확대하는 방법을 보여준다. ▶ MainWindow.xaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<Window x:Class="TestProject.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="800" Height="600" Title="TestProject" FontFamily="나눔고딕코딩" FontSize="16"> <InkCanvas Name="inkCanvas"> <InkCanvas.Background> <LinearGradientBrush> <GradientStop Offset="0.0" Color="Yellow" /> <GradientStop Offset="0.5" Color="Blue" /> <GradientStop Offset="1.0" Color="HotPink" /> </LinearGradientBrush> </InkCanvas.Background> </InkCanvas> </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 |
using System.Windows; using System.Windows.Input; using System.Windows.Media; namespace TestProject { /// <summary> /// 메인 윈도우 /// </summary> public partial class MainWindow : Window { //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - MainWindow() /// <summary> /// 생성자 /// </summary> public MainWindow() { InitializeComponent(); this.inkCanvas.MouseRightButtonUp += inkCanvas_MouseRightButtonUp; } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Private #region 잉크 캔버스 마우스 오른쪽 버튼 UP 처리하기 - inkCanvas_MouseRightButtonUp(sender, e) /// <summary> /// 잉크 캔버스 마우스 오른쪽 버튼 UP 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void inkCanvas_MouseRightButtonUp(object sender, MouseButtonEventArgs e) { Matrix matrix = new Matrix(); matrix.Scale(1.1d, 1.1d); this.inkCanvas.Strokes.Transform(matrix, true); } #endregion } } |
TestProject.zip
■ InkCanvas 엘리먼트의 Background 속성을 사용해 배경 브러시를 설정하는 방법을 보여준다. ▶ MainWindow.xaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<Window x:Class="TestProject.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="800" Height="600" Title="TestProject" FontFamily="나눔고딕코딩" FontSize="16"> <InkCanvas> <InkCanvas.Background> <LinearGradientBrush> <GradientStop Offset="0.0" Color="Yellow" /> <GradientStop Offset="0.5" Color="Blue" /> <GradientStop Offset="1.0" Color="HotPink" /> </LinearGradientBrush> </InkCanvas.Background> </InkCanvas> </Window> |
TestProject.zip
■ InkToolbar 엘리먼트의 TargetInkCanvas 속성을 사용하는 방법을 보여준다. ▶ MainPage.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 |
<Page x:Class="TestProject.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:muxc="using:Microsoft.UI.Xaml.Controls" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" FontFamily="나눔고딕코딩" FontSize="16"> <Grid> <Grid HorizontalAlignment="Center" VerticalAlignment="Center"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="50" /> <ColumnDefinition Width="Auto" /> </Grid.ColumnDefinitions> <StackPanel Grid.Column="0" BorderThickness="1" BorderBrush="Gray"> <InkToolbar Name="inkToolbar" TargetInkCanvas="{x:Bind inkCanvas}" /> <Grid Width="400" Height="400" Background="{ThemeResource SystemChromeWhiteColor}"> <InkCanvas Name="inkCanvas" /> </Grid> </StackPanel> <StackPanel Grid.Column="2" Width="180" Spacing="10"> <muxc:RadioButtons Header="펜 팁"> <RadioButton Name="circlePenTip" Content="원" Checked="penTipRadioButton_Checked" IsChecked="True" /> <RadioButton Content="사각형" Checked="penTipRadioButton_Checked" /> </muxc:RadioButtons> <Button Name="clearAll" Content="모두 지우기" Click="clearAllButton_Click" /> </StackPanel> </Grid> </Grid> </Page> |
▶ MainPage.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 |
using Windows.Foundation; using Windows.Graphics.Display; using Windows.UI.Core; using Windows.UI.Input.Inking; using Windows.UI.ViewManagement; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; namespace TestProject { /// <summary> /// 메인 페이지 /// </summary> public sealed partial class MainPage : Page { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 잉크 프리젠터 /// </summary> private InkPresenter inkPresenter; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - MainPage() /// <summary> /// 생성자 /// </summary> public MainPage() { InitializeComponent(); #region 윈도우 크기를 설정한다. double width = 800d; double height = 600d; double dpi = (double)DisplayInformation.GetForCurrentView().LogicalDpi; ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.PreferredLaunchViewSize; Size windowSize = new Size(width * 96d / dpi, height * 96d / dpi); ApplicationView.PreferredLaunchViewSize = windowSize; Window.Current.Activate(); ApplicationView.GetForCurrentView().TryResizeView(windowSize); #endregion #region 윈도우 제목을 설정한다. ApplicationView.GetForCurrentView().Title = "InkToolbar 엘리먼트 : TargetInkCanvas 속성 사용하기"; #endregion this.inkPresenter = this.inkCanvas.InkPresenter; this.inkPresenter.InputDeviceTypes = CoreInputDeviceTypes.Mouse | CoreInputDeviceTypes.Pen | CoreInputDeviceTypes.Touch; UpdatePen(); } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Private //////////////////////////////////////////////////////////////////////////////// Event #region 펜 팁 라디오 버튼 체크시 처리하기 - penTipRadioButton_Checked(sender, outedEventArgs e) /// <summary> /// 펜 팁 라디오 버튼 체크시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void penTipRadioButton_Checked(object sender, RoutedEventArgs e) { UpdatePen(); } #endregion #region 모두 지우기 버튼 클릭시 처리하기 - clearAllButton_Click(sender, e) /// <summary> /// 모두 지우기 버튼 클릭시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void clearAllButton_Click(object sender, RoutedEventArgs e) { this.inkPresenter.StrokeContainer.Clear(); } #endregion //////////////////////////////////////////////////////////////////////////////// Function #region 펜 업데이트하기 - UpdatePen() /// <summary> /// 펜 업데이트하기 /// </summary> private void UpdatePen() { if(this.inkPresenter != null) { InkDrawingAttributes defaultAttributes = this.inkPresenter.CopyDefaultDrawingAttributes(); if(defaultAttributes.Kind == InkDrawingAttributesKind.Default) { defaultAttributes.PenTip = (bool)this.circlePenTip.IsChecked ? PenTipShape.Circle : PenTipShape.Rectangle; this.inkPresenter.UpdateDefaultDrawingAttributes(defaultAttributes); } } } #endregion } } |
TestProject.zip
■ InkCanvas 엘리먼트를 사용하는 방법을 보여준다. ▶ MainPage.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 |
<Page x:Class="TestProject.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:muxc="using:Microsoft.UI.Xaml.Controls" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" FontFamily="나눔고딕코딩" FontSize="16"> <Grid> <Grid HorizontalAlignment="Center" VerticalAlignment="Center"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="50" /> <ColumnDefinition Width="Auto" /> </Grid.ColumnDefinitions> <Grid Grid.Column="0" Width="300" Height="300" BorderThickness="1" BorderBrush="Gray" Background="{ThemeResource SystemControlBackgroundChromeWhiteBrush}"> <InkCanvas Name="inkCanvas" /> </Grid> <StackPanel Grid.Column="2" Width="180" Spacing="10"> <ComboBox Name="penColorComboBox" Header="펜 색상" SelectedIndex="0" SelectionChanged="penColorComboBox_SelectionChanged"> <x:String>검정색</x:String> <x:String>빨간색</x:String> <x:String>파란색</x:String> <x:String>녹색</x:String> </ComboBox> <Slider Name="strokeSizeSlider" Header="스트로크 크기" IsFocusEngagementEnabled="False" Minimum="1" Maximum="20" Value="5" ValueChanged="strokeSizeSlider_ValueChanged" /> <CheckBox Name="drawAsHighlighterCheckBox" Content="하이라이트 그리기" IsChecked="False" Checked="drawAsHighlighterCheckBox_Checked" Unchecked="drawAsHighlighterCheckBox_Checked" /> <muxc:RadioButtons Header="펜 팁"> <RadioButton Name="circlePenTipRadioButton" Content="원" Checked="penTipRadioButton_Checked" IsChecked="True" /> <RadioButton Name="rectanglePenTipRadioButton" Content="사각형" Checked="penTipRadioButton_Checked" /> </muxc:RadioButtons> <Button Content="모두 지우기" Click="clearAllButton_Click" /> </StackPanel> </Grid> </Grid> </Page> |
▶ MainPage.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 |
using Windows.Foundation; using Windows.Graphics.Display; using Windows.UI; using Windows.UI.Core; using Windows.UI.Input.Inking; using Windows.UI.ViewManagement; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls.Primitives; namespace TestProject { /// <summary> /// 메인 페이지 /// </summary> public sealed partial class MainPage : Page { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 잉크 프리젠터 /// </summary> private InkPresenter inkPresenter; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - MainPage() /// <summary> /// 생성자 /// </summary> public MainPage() { InitializeComponent(); #region 윈도우 크기를 설정한다. double width = 800d; double height = 600d; double dpi = (double)DisplayInformation.GetForCurrentView().LogicalDpi; ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.PreferredLaunchViewSize; Size windowSize = new Size(width * 96d / dpi, height * 96d / dpi); ApplicationView.PreferredLaunchViewSize = windowSize; Window.Current.Activate(); ApplicationView.GetForCurrentView().TryResizeView(windowSize); #endregion #region 윈도우 제목을 설정한다. ApplicationView.GetForCurrentView().Title = "InkCanvas 엘리먼트 사용하기"; #endregion this.inkPresenter = this.inkCanvas.InkPresenter; this.inkPresenter.InputDeviceTypes = CoreInputDeviceTypes.Mouse | CoreInputDeviceTypes.Pen | CoreInputDeviceTypes.Touch; UpdatePen(); } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Private //////////////////////////////////////////////////////////////////////////////// Event #region 펜 색상 콤보 박스 선택 변경시 처리하기 - penColorComboBox_SelectionChanged(sender, e) /// <summary> /// 펜 색상 콤보 박스 선택 변경시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void penColorComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { UpdatePen(); } #endregion #region 스트로크 크기 슬라이더 값 변경시 처리하기 - strokeSizeSlider_ValueChanged(sender, e) /// <summary> /// 스트로크 크기 슬라이더 값 변경시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void strokeSizeSlider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e) { UpdatePen(); } #endregion #region 하이라이트 그리기 체크 박스 체크시 처리하기 - drawAsHighlighterCheckBox_Checked(sender, e) /// <summary> /// 하이라이트 그리기 체크 박스 체크시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void drawAsHighlighterCheckBox_Checked(object sender, RoutedEventArgs e) { UpdatePen(); } #endregion #region 펜 팁 라디오 버튼 체크시 처리하기 - penTipRadioButton_Checked(sender, outedEventArgs e) /// <summary> /// 펜 팁 라디오 버튼 체크시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void penTipRadioButton_Checked(object sender, RoutedEventArgs e) { UpdatePen(); } #endregion #region 모두 지우기 버튼 클릭시 처리하기 - clearAllButton_Click(sender, e) /// <summary> /// 모두 지우기 버튼 클릭시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void clearAllButton_Click(object sender, RoutedEventArgs e) { this.inkPresenter.StrokeContainer.Clear(); } #endregion //////////////////////////////////////////////////////////////////////////////// Function #region 펜 업데이트하기 - UpdatePen() /// <summary> /// 펜 업데이트하기 /// </summary> private void UpdatePen() { if(this.inkPresenter != null) { InkDrawingAttributes defaultAttributes = this.inkPresenter.CopyDefaultDrawingAttributes(); switch(this.penColorComboBox.SelectedValue.ToString()) { case "검정색" : defaultAttributes.Color = Colors.Black; break; case "빨간색" : defaultAttributes.Color = Colors.Red; break; case "파란색" : defaultAttributes.Color = Colors.Blue; break; case "녹색" : defaultAttributes.Color = Colors.Green; break; } defaultAttributes.Size = new Size(this.strokeSizeSlider.Value, this.strokeSizeSlider.Value); defaultAttributes.DrawAsHighlighter = this.drawAsHighlighterCheckBox.IsChecked.Value; defaultAttributes.PenTip = (bool)this.circlePenTipRadioButton.IsChecked ? PenTipShape.Circle : PenTipShape.Rectangle; this.inkPresenter.UpdateDefaultDrawingAttributes(defaultAttributes); } } #endregion } } |
TestProject.zip
■ Stroke 클래스의 RemovePropertyData 메소드를 사용해 속성 데이터를 제거하는 방법을 보여준다. ▶ 예제 코드 (C#)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
using System; using System.Windows.Ink; ... Stroke stroke; ... Guid timeGUID = new Guid("E41186AC-A5C7-4D01-BB43-326EED0A20DD"); if(stroke.ContainsPropertyData(timeGUID)) { stroke.RemovePropertyData(timeGUID); } |
■ Stroke 클래스의 ContainsPropertyData 메소드를 사용해 속성 데이터 포함 여부를 구하는 방법을 보여준다. ▶ 예제 코드 (C#)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
using System; using System.Windows.Ink; ... Stroke stroke; ... Guid timeGUID = new Guid("E41186AC-A5C7-4D01-BB43-326EED0A20DD"); bool contains = stroke.ContainsPropertyData(timeGUID); |
■ Stroke 클래스의 GetPropertyData 메소드를 사용해 속성 데이터를 구하는 방법을 보여준다. ▶ 예제 코드 (C#)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
using System; using System.Windows.Ink; ... Stroke stroke; ... Guid timeGUID = new Guid("E41186AC-A5C7-4D01-BB43-326EED0A20DD"); if(stroke.ContainsPropertyData(timeGUID)) { DateTime time = (DateTime)stroke.GetPropertyData(timeGUID); Console.WriteLine(time); } |