建立筆墨輸入控制項
您可以建立動態和靜態呈現筆跡的自訂控制項。 也就是說,無論是透過手寫筆、從剪貼簿貼上,或是從檔案載入,可以在使用者繪製筆劃呈現,使筆跡從手寫筆「流出」,並在筆跡新增至控制項後顯示筆跡。 為了以動態方式呈現筆跡,控制項必須使用 DynamicRenderer。 若要以靜態方式呈現筆跡,您必須覆寫手寫筆事件方法 (OnStylusDown、OnStylusMove和OnStylusUp),以收集 StylusPoint 資料、建立筆劃,並將其新增至 InkPresenter (轉譯為控制項上的筆跡)。
本主題包含下列子章節:
如何:收集手寫筆點資料並建立筆跡筆劃
若要建立可收集並管理筆跡筆劃的控制項,請執行下列動作:
從Control衍生類別,或衍生自Control的其中一個類別,例如Label。
using System; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Input.StylusPlugIns; using System.Windows.Controls; using System.Windows;
class InkControl : Label {
}
將InkPresenter新增至類別,並將Content屬性設定為新的InkPresenter。
InkPresenter ip; public InkControl() { // Add an InkPresenter for drawing. ip = new InkPresenter(); this.Content = ip; }
藉由呼叫 AttachVisuals 方法,將 DynamicRenderer 的 RootVisual 附加至 InkPresenter,並將 DynamicRenderer 新增至 StylusPlugIns 集合。 這可讓 InkPresenter 在控制項收集手寫筆點資料時顯示筆跡。
public InkControl() {
// Add a dynamic renderer that // draws ink as it "flows" from the stylus. dr = new DynamicRenderer(); ip.AttachVisuals(dr.RootVisual, dr.DrawingAttributes); this.StylusPlugIns.Add(dr); }
覆寫 OnStylusDown 方法。 在此方法中,呼叫Capture來擷取手寫筆。 藉由擷取手寫筆,即使手寫筆離開控制項的界限,您的控制項仍會繼續接收 StylusMove 和 StylusUp 事件。 這不是強制性的,但若希望有良好的使用者體驗,仍建議使用。 建立新的 StylusPointCollection 來收集 StylusPoint 資料。 最後,將初始的一組 StylusPoint 資料新增至 StylusPointCollection。
protected override void OnStylusDown(StylusDownEventArgs e) { // Capture the stylus so all stylus input is routed to this control. Stylus.Capture(this); // Allocate memory for the StylusPointsCollection and // add the StylusPoints that have come in so far. stylusPoints = new StylusPointCollection(); StylusPointCollection eventPoints = e.GetStylusPoints(this, stylusPoints.Description); stylusPoints.Add(eventPoints); }
覆寫 OnStylusMove 方法,並將 StylusPoint 資料新增至您稍早建立的 StylusPointCollection 物件。
protected override void OnStylusMove(StylusEventArgs e) { if (stylusPoints == null) { return; } // Add the StylusPoints that have come in since the // last call to OnStylusMove. StylusPointCollection newStylusPoints = e.GetStylusPoints(this, stylusPoints.Description); stylusPoints.Add(newStylusPoints); }
覆寫 OnStylusUp 方法,並使用 StylusPointCollection 資料建立新的 Stroke。 將您建立的新 Stroke 新增至 InkPresenter 和發行手寫筆擷取的 Strokes 集合。
protected override void OnStylusUp(StylusEventArgs e) { if (stylusPoints == null) { return; } // Add the StylusPoints that have come in since the // last call to OnStylusMove. StylusPointCollection newStylusPoints = e.GetStylusPoints(this, stylusPoints.Description); stylusPoints.Add(newStylusPoints); // Create a new stroke from all the StylusPoints since OnStylusDown. Stroke stroke = new Stroke(stylusPoints); // Add the new stroke to the Strokes collection of the InkPresenter. ip.Strokes.Add(stroke); // Clear the StylusPointsCollection. stylusPoints = null; // Release stylus capture. Stylus.Capture(null); }
如何:啟用控制項以接受滑鼠輸入
如果您將上述控制項新增至應用程式,並在執行後以滑鼠作為輸入裝置,您會發現筆劃不會保存。 若要在使用滑鼠作為輸入裝置時保存筆劃,請執行下列動作:
覆寫 OnMouseLeftButtonDown 並建立新的 StylusPointCollection 取得事件發生時滑鼠的位置,並使用點數據建立 StylusPoint ,並將 StylusPoint 新增至 StylusPointCollection。
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) { base.OnMouseLeftButtonDown(e); // If a stylus generated this event, return. if (e.StylusDevice != null) { return; } // Start collecting the points. stylusPoints = new StylusPointCollection(); Point pt = e.GetPosition(this); stylusPoints.Add(new StylusPoint(pt.X, pt.Y)); }
覆寫 OnStylusDown 方法。 取得事件發生時滑鼠的位置,並使用點資料建立StylusPoint。 將 StylusPoint 新增至您稍早建立的 StylusPointCollection 物件。
protected override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); // If a stylus generated this event, return. if (e.StylusDevice != null) { return; } // Don't collect points unless the left mouse button // is down. if (e.LeftButton == MouseButtonState.Released || stylusPoints == null) { return; } Point pt = e.GetPosition(this); stylusPoints.Add(new StylusPoint(pt.X, pt.Y)); }
覆寫 OnStylusDown 方法。 使用 StylusPointCollection 資料建立新的 Stroke ,並將您建立的新 Stroke 新增至 InkPresenter 的 Strokes集合。
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) { base.OnMouseLeftButtonUp(e); // If a stylus generated this event, return. if (e.StylusDevice != null) { return; } if (stylusPoints == null) { return; } Point pt = e.GetPosition(this); stylusPoints.Add(new StylusPoint(pt.X, pt.Y)); // Create a stroke and add it to the InkPresenter. Stroke stroke = new Stroke(stylusPoints); stroke.DrawingAttributes = dr.DrawingAttributes; ip.Strokes.Add(stroke); stylusPoints = null; }
將它放在一起
下列範例是在使用者使用滑鼠或手寫筆時,收集筆跡的自訂控制項。
using System;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Input.StylusPlugIns;
using System.Windows.Controls;
using System.Windows;
// A control for managing ink input
class InkControl : Label
{
InkPresenter ip;
DynamicRenderer dr;
// The StylusPointsCollection that gathers points
// before Stroke from is created.
StylusPointCollection stylusPoints = null;
public InkControl()
{
// Add an InkPresenter for drawing.
ip = new InkPresenter();
this.Content = ip;
// Add a dynamic renderer that
// draws ink as it "flows" from the stylus.
dr = new DynamicRenderer();
ip.AttachVisuals(dr.RootVisual, dr.DrawingAttributes);
this.StylusPlugIns.Add(dr);
}
static InkControl()
{
// Allow ink to be drawn only within the bounds of the control.
Type owner = typeof(InkControl);
ClipToBoundsProperty.OverrideMetadata(owner,
new FrameworkPropertyMetadata(true));
}
protected override void OnStylusDown(StylusDownEventArgs e)
{
// Capture the stylus so all stylus input is routed to this control.
Stylus.Capture(this);
// Allocate memory for the StylusPointsCollection and
// add the StylusPoints that have come in so far.
stylusPoints = new StylusPointCollection();
StylusPointCollection eventPoints =
e.GetStylusPoints(this, stylusPoints.Description);
stylusPoints.Add(eventPoints);
}
protected override void OnStylusMove(StylusEventArgs e)
{
if (stylusPoints == null)
{
return;
}
// Add the StylusPoints that have come in since the
// last call to OnStylusMove.
StylusPointCollection newStylusPoints =
e.GetStylusPoints(this, stylusPoints.Description);
stylusPoints.Add(newStylusPoints);
}
protected override void OnStylusUp(StylusEventArgs e)
{
if (stylusPoints == null)
{
return;
}
// Add the StylusPoints that have come in since the
// last call to OnStylusMove.
StylusPointCollection newStylusPoints =
e.GetStylusPoints(this, stylusPoints.Description);
stylusPoints.Add(newStylusPoints);
// Create a new stroke from all the StylusPoints since OnStylusDown.
Stroke stroke = new Stroke(stylusPoints);
// Add the new stroke to the Strokes collection of the InkPresenter.
ip.Strokes.Add(stroke);
// Clear the StylusPointsCollection.
stylusPoints = null;
// Release stylus capture.
Stylus.Capture(null);
}
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
// If a stylus generated this event, return.
if (e.StylusDevice != null)
{
return;
}
// Start collecting the points.
stylusPoints = new StylusPointCollection();
Point pt = e.GetPosition(this);
stylusPoints.Add(new StylusPoint(pt.X, pt.Y));
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
// If a stylus generated this event, return.
if (e.StylusDevice != null)
{
return;
}
// Don't collect points unless the left mouse button
// is down.
if (e.LeftButton == MouseButtonState.Released ||
stylusPoints == null)
{
return;
}
Point pt = e.GetPosition(this);
stylusPoints.Add(new StylusPoint(pt.X, pt.Y));
}
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonUp(e);
// If a stylus generated this event, return.
if (e.StylusDevice != null)
{
return;
}
if (stylusPoints == null)
{
return;
}
Point pt = e.GetPosition(this);
stylusPoints.Add(new StylusPoint(pt.X, pt.Y));
// Create a stroke and add it to the InkPresenter.
Stroke stroke = new Stroke(stylusPoints);
stroke.DrawingAttributes = dr.DrawingAttributes;
ip.Strokes.Add(stroke);
stylusPoints = null;
}
}
使用其他外掛程式和 DynamicRenderers
如同 InkCanvas,您的自訂控制項可以有自訂 StylusPlugIn 和其他 DynamicRenderer 物件。 將這些新增至 StylusPlugIns 集合。 在 StylusPlugInCollection 中,StylusPlugIn 物件的順序會影響轉譯時筆跡顯示的外觀。 假設您有名為 dynamicRenderer
的 DynamicRenderer,以及稱為 translatePlugin
的自訂 StylusPlugIn,會從平板電腦手寫筆中位移筆跡。 如果 translatePlugin
是 StylusPlugInCollection 中的第一個 StylusPlugIn,而 dynamicRenderer
是第二個,當使用者移動手寫筆時,「流出」的筆跡將會位移。 如果 dynamicRenderer
是第一個,且 translatePlugin
為第二個,則在手寫筆被使用者移開之前,筆跡將不會位移。
結論
您可以覆寫手寫筆事件方法,建立能收集和轉譯筆跡的控制項。 藉由建立自己的控制項、衍生自己的 StylusPlugIn 類別,並將其插入 StylusPlugInCollection,您幾乎可以實作任何想像得到的數位筆跡行為。 您可以存取產生的 StylusPoint 資料,就能夠自訂 Stylus 輸入,並視應用程式的情況在畫面上轉譯。 由於您對 StylusPoint 資料具有低層級存取權,因此您可以實作筆跡集合,並以應用程式的最佳效能轉譯。