詳解WPF的InkCanvas選擇模式
InkCanvas是WPF中進(jìn)行墨跡繪制的控件,本文介紹下InkCanvas控件是如何進(jìn)行選擇操作的。文中有誤的地方希望大家進(jìn)行批評(píng)指正。
InkCanvas的選擇效果
使用WPF可以輕松實(shí)現(xiàn)白板功能,只需要添加一個(gè)InkCanvas控件。修改InkCanvas的EditingMode屬性可以控制InkCanvas的操作模式,如書(shū)寫(xiě)、選擇、擦除等模式。
如下demo在窗口中添加一個(gè)InkCanvas,然后添加一個(gè)Button實(shí)現(xiàn)書(shū)寫(xiě)與選擇模式的切換。
// xaml <Grid> <InkCanvas x:Name="inkCanvas"/> <Button x:Name="btnChangeMode" Content="select" Click="Button_Click" Width="50" Height="30" HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="10"/> </Grid> // cs private void Button_Click(object sender, RoutedEventArgs e) { if(btnChangeMode.Content == "select") { inkCanvas.EditingMode = InkCanvasEditingMode.Select; btnChangeMode.Content = "write"; } else { inkCanvas.EditingMode = InkCanvasEditingMode.Ink; btnChangeMode.Content = "select"; } }
運(yùn)行demo,書(shū)寫(xiě)后點(diǎn)擊按鈕進(jìn)行選擇,可以看到InkCanvas的選擇操作如下圖所示:
從圖中可以看出,InkCanvas的選擇效果有如下特點(diǎn):
- 選中后筆跡高亮;
- 選中后顯示選擇框;
- 拖動(dòng)選擇框,選擇框隨著鼠標(biāo)移動(dòng),但選擇的筆跡并未移動(dòng)。
接下來(lái)看下WPF是如何實(shí)現(xiàn)這種選擇操作的。
InkCanvas選擇模式的實(shí)現(xiàn)
首先,InkCanvas的編輯功能(書(shū)寫(xiě)、擦除、選擇等)是通過(guò)EditingCoordinator管理的,該類包含一系列的EditingBehavior,實(shí)現(xiàn)選擇過(guò)程的為L(zhǎng)assoSelectionBehavior類,實(shí)現(xiàn)選擇后對(duì)選擇框操作的為SelectionEditor與SelectionEditingBehavior。本文主要介紹選擇后對(duì)選擇框的操作過(guò)程,選擇過(guò)程以及筆跡的高亮顯示打算單獨(dú)寫(xiě)一篇文章進(jìn)行介紹。
在InkCanvas中,與選擇功能相關(guān)的對(duì)象有InkCanvasSelection、InkCanvasSelectionAdorner及InkCanvasFeedbackAdorner。后兩者為裝飾器,裝飾器的介紹可參考官方文檔。
先看InkCanvasSelectionAdorner類,直接看其OnRender方法,代碼如下。首先繪制了選擇框的背景,然后繪制了選擇框(矩形虛線效果),最后繪制了選擇框上的9個(gè)小矩形按鈕。按鈕可以進(jìn)行拖動(dòng)調(diào)節(jié),具體實(shí)現(xiàn)邏輯可以看代碼,本文不贅述。
protected override void OnRender(DrawingContext drawingContext) { DrawBackground(drawingContext); Rect rectWireFrame = GetWireFrameRect() if(!rectWireFrame.IsEmpty) { drawingContext.DrawRectangle(null, _adornerBorderPen, rectWireFrame); DrawHandles(drawingContext, rectWireFrame); } }
再看InkCanvasFeedbackAdorner類,同樣看OnRender方法,代碼如下。其僅繪制了矩形虛線選擇框,通過(guò)這兩個(gè)類的OnRender方法,結(jié)合上文中的動(dòng)畫(huà),可以知道選中后使用InkCanvasSelectionAdorner進(jìn)行裝飾,對(duì)選擇框的操作(拖動(dòng))使用InkCanvasFeedbackAdorner進(jìn)行裝飾。
protected override void OnRender(DrawingContext drawingContext) { drawingContext.DrawRectangle(null, _adornerBorderPen, new Rect(CornerResizeHandleSize / 2, CornerResizeHandleSize / 2, _frameSize.Width - CornerResizeHandleSize, _frameSize.Height - CornerResizeHandleSize)); }
接下來(lái)看下這兩個(gè)Adorner是對(duì)誰(shuí)進(jìn)行裝飾的,首先看InkCanvas的OnPreApplyTemplate方法,代碼如下。注釋部分是InkCanvas的Visual Tree,可以了解到InkCanvas的內(nèi)部結(jié)構(gòu)。再看下SelectionAdorner的初始化,可以看出是對(duì)InnerCanvas進(jìn)行裝飾,InnerCanvas是InkCanvas的內(nèi)部容器,放置筆跡及其它UIElement。SelectionAdorner添加了對(duì)ActiveEditingMode的綁定,當(dāng)Mode為None時(shí),隱藏,否則顯示。FeedbackAdorner的裝飾對(duì)象通過(guò)其構(gòu)造函數(shù)可以看出,也是裝飾的InnerCanvas。
internal override void OnPreApplyTemplate() { base.OnPreApplyTemplate(); // Build our visual tree here. // <InkCanvas> // <AdornerDecorator> // <InkPresenter> // <InnerCanvas/> // <ContainerVisual/> // <HostVisual/> // </InkPresenter> // <AdornerLayer> // <InkCanvasSelectionAdorner/> // <InkCanvasFeedbackAdorner/> // </AdornerLayer> // </AdornerDecorator> // </InkCanvas> if(_localAdornerDecorator == null) { _localAdornerDecorator = new AdornerDecorator(); InkPresenter inkPresenter = InkPresenter; AddVisualChild(_localAdornerDecorator); _localAdornerDecorator.Child = inkPresenter; inkPresenter.Child = InnerCanvas; _localAdornerDecorator.AdornerLayer.Add(SelectionAdorner); } } internal InkCanvasSelectionAdorner SelectionAdorner { get { if(_selectionAdorner == null) { _selectionAdorner = new InkCanvasSelectionAdorner(InnerCanvas); Binding activedEditingModeBinding = new Binding(); activedEditingModeBinding.Path = new PropertyPath(InkCanvas.ActiveEditingModeProperty); activedEditingModeBinding.Mode = BindingMode.OneWay; activedEditingModeBinding.Source = this; activedEditingModeBinding.Converter = new ActiveEditingMode2VisibilityConverter(); _selectionAdorner.SetBinding(UIElement.VisibilityProperty, activedEditingModeBinding); } return _selectionAdorner; } } // InkCanvasFeedbackAdorner internal InkCanvasFeedbackAdorner(InkCanvas inkCanvas) : base((inkCanvas != null ? inkCanvas.InnerCanvas : null)) {...}
最后,我們看下對(duì)選擇框進(jìn)行的操作是如何實(shí)現(xiàn)的。選擇后會(huì)激活SelectionEditingBehavior,在其OnActivate方法中,綁定了SelectionAdorner的MouseMove/MouseUp/LostMouseCapture事件,并調(diào)用InkCanvasSelection.StartFeedbackAdorner()方法對(duì)FeedbackAdorner進(jìn)行初始化,將其添加到AdornerLayer中。然后通過(guò)響應(yīng)MouseMove,調(diào)用InkSelection.UpdateFeedbackAdorner()方法更新FeedbackAdorner的位置。最后在MouseUp響應(yīng)中釋放FeedbackAdorner。刪減代碼如下,具體的實(shí)現(xiàn)邏輯可以看WPF源碼。
protected override void OnActive() { // ... InkCanvas.InkCanvasSelection.StartFeedbackAdorner(_selectionRect, _hitResult); InkCanvas.SelectionAdorner.AddHandler(Mouse.MouseUpEvent, new MouseButtonEventHandler(OnMouseUp)); InkCanvas.SelectionAdorner.AddHandler(Mouse.MouseMoveEvent, new MouseEventHandler(OnMouseMove)); InkCanvas.SelectionAdorner.AddHandler(Mouse.LostMouseCaptureEvent, new MouseEventHandler(OnLostMouseCapture)); } private void OnMouseMove(object sender, MouseEventArgs args) { // ... InkCanvas.InkCanvasSelection.UpdateFeedbackAdorner(newRect); // ... }
以上就是詳解WPF的InkCanvas選擇模式的詳細(xì)內(nèi)容,更多關(guān)于WPF的InkCanvas選擇模式的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- C# WPF實(shí)現(xiàn)的語(yǔ)音播放自定義控件
- c# wpf如何更好的使用Application程序集資源
- 通過(guò)App.xaml理解wpf中的Application類
- 詳解WPF中的隧道路由和冒泡路由事件
- C# WPF如何反射加載Geometry幾何圖形數(shù)據(jù)圖標(biāo)
- c# wpf如何附加依賴項(xiàng)屬性
- c# WPF中的TreeView使用詳解
- c# wpf如何使用Blend工具繪制Control樣式
- c# 基于GMap.NET實(shí)現(xiàn)電子圍欄功能(WPF版)
- c# wpf使用GMap.NET類庫(kù),實(shí)現(xiàn)地圖軌跡回放
- 詳解WPF中的對(duì)象資源
相關(guān)文章
C#和JavaScript實(shí)現(xiàn)交互的方法
最近做一個(gè)小項(xiàng)目不可避免的需要前端腳本與后臺(tái)進(jìn)行交互。由于是在asp.net中實(shí)現(xiàn),故問(wèn)題演化成asp.net中jiavascript與后臺(tái)c#如何進(jìn)行交互。2015-05-05C#中TreeView節(jié)點(diǎn)的自定義繪制方法
這篇文章主要介紹了C#中TreeView節(jié)點(diǎn)的自定義繪制方法,實(shí)例展示了TreeView節(jié)點(diǎn)的操作技巧,需要的朋友可以參考下2015-02-02c#文件的復(fù)制,移動(dòng),創(chuàng)建(實(shí)例代碼)
c#文件的復(fù)制,移動(dòng),創(chuàng)建(實(shí)例代碼),需要的朋友可以參考一下2013-04-04c#多線程中Lock()關(guān)鍵字的用法小結(jié)
本篇文章主要是對(duì)c#多線程中Lock()關(guān)鍵字的用法進(jìn)行了詳細(xì)的總結(jié)介紹,需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助2014-01-01winform實(shí)現(xiàn)創(chuàng)建最前端窗體的方法
這篇文章主要介紹了winform實(shí)現(xiàn)創(chuàng)建最前端窗體的方法,涉及C#窗體屬性設(shè)置的相關(guān)技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-08-08C# 獲取動(dòng)態(tài)key的json對(duì)象的值案例
這篇文章主要介紹了C# 獲取動(dòng)態(tài)key的json對(duì)象的值案例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-01-01