UWP app 中的手寫筆互動與 Windows InkPen interactions and Windows Ink in UWP apps

介面的畫筆Surface Pen
Surface 手寫筆 (可在 Microsoft 網上商店購買)。Surface Pen (available for purchase at the Microsoft Store).

總覽Overview

最佳化您的通用 Windows 平台 (UWP) app,讓手寫筆輸入能夠為您的使用者提供標準指標裝置功能和最好的 Windows Ink 體驗。Optimize your Universal Windows Platform (UWP) app for pen input to provide both standard pointer device functionality and the best Windows Ink experience for your users.

注意

本主題著重在 Windows Ink 平台。This topic focuses on the Windows Ink platform. 如需了解一般指標輸入處理 (類似於滑鼠、觸控及觸控板),請參閱處理指標輸入For general pointer input handling (similar to mouse, touch, and touchpad), see Handle pointer input.

影片Videos
使用 UWP 應用程式中的筆墨Using ink in your UWP app 使用 Windows 手寫筆和筆跡建置更吸引人的企業應用程式Use Windows Pen and Ink to build more engaging enterprise apps

Windows Ink 平台搭配手寫筆裝置之後,使用者就可以自然的方式建立數位手寫筆記、繪圖以及註解。The Windows Ink platform, together with a pen device, provides a natural way to create digital handwritten notes, drawings, and annotations. 此平台支援擷取數位板輸入做為筆墨資料、產生筆墨資料、管理筆墨資料、在輸出裝置上將筆墨資料轉譯為筆劃,以及透過手寫辨識將筆墨轉換為文字。The platform supports capturing digitizer input as ink data, generating ink data, managing ink data, rendering ink data as ink strokes on the output device, and converting ink to text through handwriting recognition.

除了在使用者書寫或繪圖時抓取畫筆的基本位置和移動,您的 app 也可以追蹤並收集整個筆劃中所使用的壓力變動量。In addition to capturing the basic position and movement of the pen as the user writes or draws, your app can also track and collect the varying amounts of pressure used throughout a stroke. 此資訊以及適用於筆尖形狀、大小及旋轉、筆墨色彩和用途 (一般筆墨、清除、反白顯示及選取) 的設定,可讓您提供非常類似在紙上使用筆、鉛筆或筆刷書寫或繪圖的使用者經驗。This information, along with settings for pen tip shape, size, and rotation, ink color, and purpose (plain ink, erasing, highlighting, and selecting), enables you to provide user experiences that closely resemble writing or drawing on paper with a pen, pencil, or brush.

注意

您的 app 也可以支援來自其他指標型裝置的筆墨輸入,包括觸控數位板和滑鼠裝置。Your app can also support ink input from other pointer-based devices, including touch digitizers and mouse devices. 

筆跡平台的彈性非常大。The ink platform is very flexible. 根據您的需求,它是專為支援各種不同層級的功能而設計。It is designed to support various levels of functionality, depending on your requirements.

如需 Windows Ink UX 指導方針,請參閱筆跡控制項For Windows Ink UX guidelines, see Inking controls.

Windows Ink 平台的元件Components of the Windows Ink platform

ComponentComponent 描述Description
InkCanvasInkCanvas XAML UI 平台的控制項,根據預設,會接收並顯示所有的輸入,來自手寫筆筆墨筆劃或清除筆劃。A XAML UI platform control that, by default, receives and displays all input from a pen as either an ink stroke or an erase stroke.
如需如何使用 InkCanvas 的詳細資訊,請參閱將 Windows Ink 筆觸辨識為文字儲存和抓取 Windows Ink 筆觸資料For more information about how to use the InkCanvas, see Recognize Windows Ink strokes as text and Store and retrieve Windows Ink stroke data.
InkPresenterInkPresenter 程式碼後置物件,連同 InkCanvas 控制項 (透過 InkCanvas.InkPresenter 屬性所公開) 進行具現化。A code-behind object, instantiated along with an InkCanvas control (exposed through the InkCanvas.InkPresenter property). 這個物件提供 InkCanvas 公開的所有預設筆跡功能,以及一組完整的 API 來進行其他自訂和個人化。This object provides all default inking functionality exposed by the InkCanvas, along with a comprehensive set of APIs for additional customization and personalization.
如需如何使用 InkPresenter 的詳細資訊,請參閱將 Windows Ink 筆觸辨識為文字儲存和抓取 Windows Ink 筆觸資料For more information about how to use the InkPresenter, see Recognize Windows Ink strokes as text and Store and retrieve Windows Ink stroke data.
InkToolbarInkToolbar XAML UI 平台控制項包含自訂和擴充集合的 啟動中相關聯的筆跡相關功能的按鈕 InkCanvasA XAML UI platform control containing a customizable and extensible collection of buttons that activate ink-related features in an associated InkCanvas.
如需如何使用 InkToolbar 的詳細資訊,請參閱將 InkToolbar 新增至通用 Windows 平台 (UWP) 手寫筆跡應用程式For more information about how to use the InkToolbar, see Add an InkToolbar to a Universal Windows Platform (UWP) inking app.
IInkD2DRendererIInkD2DRenderer 可讓筆墨筆劃轉譯到通用 Windows app 的指定 Direct2D 裝置內容,而不是預設的 InkCanvas 控制項。Enables the rendering of ink strokes onto the designated Direct2D device context of a Universal Windows app, instead of the default InkCanvas control. 這樣就能完整自訂筆跡體驗。This enables full customization of the inking experience.
如需詳細資訊,請參閱複雜的筆跡範例For more information, see the Complex ink sample.

利用 InkCanvas 的基本筆跡功能Basic inking with InkCanvas

若要新增基本筆跡功能,只要將 InkCanvas UWP 平台控制項放在您的應用程式中的適當頁面上。To add basic inking functionality, just place an InkCanvas UWP platform control on the appropriate page in your app.

根據預設,InkCanvas 僅支援來自畫筆的筆跡輸入。By default, the InkCanvas supports ink input only from a pen. 輸入是使用色彩及粗細的預設設定 (黑色鋼珠筆,2 點像素粗細) 轉譯為筆墨筆劃,或可視為筆劃橡皮擦 (若輸入是來自橡皮擦筆尖,或使用橡皮擦按鈕修改的筆尖)。The input is either rendered as an ink stroke using default settings for color and thickness (a black ballpoint pen with a thickness of 2 pixels), or treated as a stroke eraser (when input is from an eraser tip or the pen tip modified with an erase button).

注意

如果橡皮擦筆尖或按鈕不存在,InkCanvas 可以設定為將筆尖輸入做為擦去筆劃處理。If an eraser tip or button is not present, the InkCanvas can be configured to process input from the pen tip as an erase stroke.

在這個範例中,InkCanvas 會重疊背景影像。In this example, an InkCanvas overlays a background image.

注意

InkCanvas 有預設值高度寬度屬性為零,除非它是元素的子系是自動調整大小其子項目,例如StackPanel或是格線控制項。An InkCanvas has default Height and Width properties of zero, unless it is the child of an element that automatically sizes its child elements, such as StackPanel or Grid controls.

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <StackPanel x:Name="HeaderPanel" Orientation="Horizontal" Grid.Row="0">
        <TextBlock x:Name="Header"
                   Text="Basic ink sample"
                   Style="{ThemeResource HeaderTextBlockStyle}"
                   Margin="10,0,0,0" />            
    </StackPanel>
    <Grid Grid.Row="1">
        <Image Source="Assets\StoreLogo.png" />
        <InkCanvas x:Name="inkCanvas" />
    </Grid>
</Grid>

這系列的影像會顯示這個 InkCanvas 控制項轉譯畫筆輸入的方式。This series of images shows how pen input is rendered by this InkCanvas control.

含有背景影像的空白 InkCanvas 含有筆墨筆劃的 InkCanvas 已擦掉一個筆劃的 InkCanvas
含有背景影像的空白 InkCanvasThe blank InkCanvas with a background image. 含有筆墨筆劃的 InkCanvasThe InkCanvas with ink strokes. 已擦掉一個筆畫的 InkCanvas (請注意,此功能會擦掉整個筆劃,而不是擦掉部分筆劃)。The InkCanvas with one stroke erased (note how erase operates on an entire stroke, not a portion).

InkCanvas 控制項支援的筆墨功能是由名為 InkPresenter 的程式碼後置物件所提供。The inking functionality supported by the InkCanvas control is provided by a code-behind object called the InkPresenter.

針對基本的筆墨功能,您不需要考慮使用 InkPresenterFor basic inking, you don't have to concern yourself with the InkPresenter. 不過,若要在 InkCanvas 上自訂和設定筆墨行為,您就必須存取其對應的 InkPresenter 物件。However, to customize and configure inking behavior on the InkCanvas, you must access its corresponding InkPresenter object.

使用 InkPresenter 的基本自訂Basic customization with InkPresenter

InkPresenter 物件是利用每個 InkCanvas 控制項來具現化。An InkPresenter object is instantiated with each InkCanvas control.

注意

InkPresenter 不會直接具現化。The InkPresenter cannot be instantiated directly. 而是透過 InkCanvasInkPresenter 屬性來存取。Instead, it is accessed through the InkPresenter property of the InkCanvas. 

除了提供其對應 InkCanvas 控制項的所有預設筆墨行為,InkPresenter 也會提供一組完整的 API 來進行額外的筆劃自訂,並更細部地管理手寫筆輸入 (標準和已修改的)。Along with providing all default inking behaviors of its corresponding InkCanvas control, the InkPresenter provides a comprehensive set of APIs for additional stroke customization and finer-grained management of the pen input (standard and modified). 這包括筆劃屬性、支援的輸入裝置類型,以及輸入是否是由物件所處理或者會傳遞到應用程式進行處理。This includes stroke properties, supported input device types, and whether input is processed by the object or passed to the app for processing.

注意

標準筆跡輸入 (從手寫筆筆尖或橡皮擦/按鈕) 不會使用次要硬體能供性 (例如手寫筆筒狀按鈕、滑鼠右鍵或類似的機制) 進行修改。Standard ink input (from either pen tip or eraser tip/button) is not modified with a secondary hardware affordance, such as a pen barrel button, right mouse button, or similar mechanism.

根據預設,筆跡功能只支援手寫筆輸入。By default, ink is supported for pen input only. 我們會在此處設定InkPresenter,將來自畫筆和滑鼠的輸入資料解譯為筆墨筆劃。Here, we configure the InkPresenter to interpret input data from both pen and mouse as ink strokes. 我們也會設定一些初始筆墨筆劃屬性,以用來將筆劃轉譯到 InkCanvasWe also set some initial ink stroke attributes used for rendering strokes to the InkCanvas.

若要啟用滑鼠和觸控筆跡,請將 InputDeviceTypes 屬性的 InkPresenter 設定為您想要的 CoreInputDeviceTypes 值的組合。To enable mouse and touch inking, set the InputDeviceTypes property of the InkPresenter to the combination of CoreInputDeviceTypes values that you want.

public MainPage()
{
    this.InitializeComponent();

    // Set supported inking device types.
    inkCanvas.InkPresenter.InputDeviceTypes =
        Windows.UI.Core.CoreInputDeviceTypes.Mouse |
        Windows.UI.Core.CoreInputDeviceTypes.Pen;

    // Set initial ink stroke attributes.
    InkDrawingAttributes drawingAttributes = new InkDrawingAttributes();
    drawingAttributes.Color = Windows.UI.Colors.Black;
    drawingAttributes.IgnorePressure = false;
    drawingAttributes.FitToCurve = true;
    inkCanvas.InkPresenter.UpdateDefaultDrawingAttributes(drawingAttributes);
}

您可以動態設定筆墨筆劃屬性,以適應使用者的喜好設定或 app 需求。Ink stroke attributes can be set dynamically to accommodate user preferences or app requirements.

我們將在此處讓使用者可從筆墨色彩清單中進行選擇。Here, we let a user choose from a list of ink colors.

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <StackPanel x:Name="HeaderPanel" Orientation="Horizontal" Grid.Row="0">
        <TextBlock x:Name="Header"
                   Text="Basic ink customization sample"
                   VerticalAlignment="Center"
                   Style="{ThemeResource HeaderTextBlockStyle}"
                   Margin="10,0,0,0" />
        <TextBlock Text="Color:"
                   Style="{StaticResource SubheaderTextBlockStyle}"
                   VerticalAlignment="Center"
                   Margin="50,0,10,0"/>
        <ComboBox x:Name="PenColor"
                  VerticalAlignment="Center"
                  SelectedIndex="0"
                  SelectionChanged="OnPenColorChanged">
            <ComboBoxItem Content="Black"/>
            <ComboBoxItem Content="Red"/>
        </ComboBox>
    </StackPanel>
    <Grid Grid.Row="1">
        <Image Source="Assets\StoreLogo.png" />
        <InkCanvas x:Name="inkCanvas" />
    </Grid>
</Grid>

接著處理選取色彩的變更,並據此更新筆墨筆劃屬性。We then handle changes to the selected color and update the ink stroke attributes accordingly.

// Update ink stroke color for new strokes.
private void OnPenColorChanged(object sender, SelectionChangedEventArgs e)
{
    if (inkCanvas != null)
    {
        InkDrawingAttributes drawingAttributes =
            inkCanvas.InkPresenter.CopyDefaultDrawingAttributes();

        string value = ((ComboBoxItem)PenColor.SelectedItem).Content.ToString();

        switch (value)
        {
            case "Black":
                drawingAttributes.Color = Windows.UI.Colors.Black;
                break;
            case "Red":
                drawingAttributes.Color = Windows.UI.Colors.Red;
                break;
            default:
                drawingAttributes.Color = Windows.UI.Colors.Black;
                break;
        };

        inkCanvas.InkPresenter.UpdateDefaultDrawingAttributes(drawingAttributes);
    }
}

這些影像說明 InkPresenter 如何處理和自訂畫筆輸入。These images shows how pen input is processed and customized by the InkPresenter.

含有預設黑色筆墨筆劃的 InkCanvas 含有使用者選取的紅色筆墨筆劃的 InkCanvas
含有預設黑色筆墨筆劃的 InkCanvasThe InkCanvas with default black ink strokes. 含有使用者選取的紅色筆墨筆劃的 InkCanvasThe InkCanvas with user selected red ink strokes.  

若要提供筆墨和擦掉之後的功能 (例如選取筆劃),您的 app 必須針對 InkPresenter 識別出未經處理即可傳入的特定輸入,讓您的 app 來處理。To provide functionality beyond inking and erasing, such as stroke selection, your app must identify specific input for the InkPresenter to pass through unprocessed for handling by your app.

傳入輸入以進行進階處理Pass-through input for advanced processing

根據預設,InkPresenter 會將所有輸入處理為筆墨筆劃或擦去筆劃,包括由次要硬體能供性 (例如筆身按鈕、滑鼠右鍵按鈕等) 修改的輸入。By default, InkPresenter processes all input as either an ink stroke or an erase stroke, including input modified by a secondary hardware affordance such as a pen barrel button, a right mouse button, or similar. 但是,使用這些次要能供性時,使用者通常會預期一些額外的功能或已修改的行為。However, users typically expect some additional functionality or modified behavior with these secondary affordances.

在某些情況下,您可能也需要公開適用於畫筆的額外功能,而不需次要能供性 (通常不會與筆尖相關聯的功能)、其他輸入裝置類型或額外功能,或者根據應用程式 UI 中的使用者選取項目進行的某些類型修改行為。In some cases, you might also need to expose additional functionality for pens without secondary affordances (functionality not usually associated with the pen tip), other input device types, or some type of modified behavior based on a user selection in your app's UI.

若要支援這一點,可設定 InkPresenter 來讓特定的輸入保持未處理狀態。To support this, InkPresenter can be configured to leave specific input unprocessed. 這個未處理的輸入接著會傳入您的 app 進行處理。This unprocessed input is then passed through to your app for processing.

範例 - 使用未處理的輸入實作筆觸選取Example - Use unprocessed input to implement stroke selection

Windows Ink 平台不提供需要修改輸入 (例如筆觸選取項目) 動作的內建支援。The Windows Ink platform does not provide built-in support for actions that require modified input, such as stroke selection. 若要支援像這樣的功能,您必須在您的應用程式中提供自訂解決方案。To support features like this, you must provide a custom solution in your apps.

下列程式碼範例 (所有的程式碼都位於 MainPage.xaml 和 MainPage.xaml.cs 檔案) 會逐步解說如何在使用畫筆筆身按鈕 (或滑鼠右鍵按鈕) 修改輸入時啟用筆劃選項的方法。The following code example (all code is in the MainPage.xaml and MainPage.xaml.cs files) steps through how to enable stroke selection when input is modified with a pen barrel button (or right mouse button).

  1. 首先,在 MainPage.xaml 中設定 UI。First, we set up the UI in MainPage.xaml.

    我們將在此處新增畫布 (位於 InkCanvas 下方) 來繪製選取筆劃。Here, we add a canvas (below the InkCanvas) to draw the selection stroke. 使用個別層級來繪製選取筆劃,讓 InkCanvas 及其內容保持原貌。Using a separate layer to draw the selection stroke leaves the InkCanvas and its content untouched.

    含有基礎選取項目畫布的空白 InkCanvas

      <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
          <RowDefinition Height="Auto"/>
          <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <StackPanel x:Name="HeaderPanel" Orientation="Horizontal" Grid.Row="0">
          <TextBlock x:Name="Header"
            Text="Advanced ink customization sample"
            VerticalAlignment="Center"
            Style="{ThemeResource HeaderTextBlockStyle}"
            Margin="10,0,0,0" />
        </StackPanel>
        <Grid Grid.Row="1">
          <!-- Canvas for displaying selection UI. -->
          <Canvas x:Name="selectionCanvas"/>
          <!-- Inking area -->
          <InkCanvas x:Name="inkCanvas"/>
        </Grid>
      </Grid>
    
  2. 在 MainPage.xaml.cs 中,我們會宣告數個全域變數,持續參考各個層面的 UI 選取項目。In MainPage.xaml.cs, we declare a couple of global variables for keeping references to aspects of the selection UI. 具體而言,選取套索筆劃和週框會將選取的筆劃反白顯示。Specifically, the selection lasso stroke and the bounding rectangle that highlights the selected strokes.

      // Stroke selection tool.
      private Polyline lasso;
      // Stroke selection area.
      private Rect boundingRect;
    
  3. 接下來,我們會設定 InkPresenter,將來自畫筆和滑鼠的輸入資料解譯為筆墨筆劃,並設定一些初始的筆墨筆劃屬性,以用來將筆劃轉譯到 InkCanvasNext, we configure the InkPresenter to interpret input data from both pen and mouse as ink strokes, and set some initial ink stroke attributes used for rendering strokes to the InkCanvas.

    最重要的是,我們會使用 InkPresenterInputProcessingConfiguration 屬性來表示 app 應該處理所有修改的輸入。Most importantly, we use the InputProcessingConfiguration property of the InkPresenter to indicate that any modified input should be processed by the app. 修改的輸入是藉由指派 InkInputRightDragAction.LeaveUnprocessedInputProcessingConfiguration.RightDragAction 值來指定。Modified input is specified by assigning InputProcessingConfiguration.RightDragAction a value of InkInputRightDragAction.LeaveUnprocessed. 當設定此值時,InkPresenter 會通過並抵達 InkUnprocessedInput 類別 - 可讓您處理的一系列指標事件。When this value is set, the InkPresenter passes through to the InkUnprocessedInput class, a set of pointer events for you to handle.

    我們會針對未處理的 PointerPressedPointerMovedPointerReleased 事件指派接聽程式,這些事件是透過 InkPresenter 來傳入。We assign listeners for the unprocessed PointerPressed, PointerMoved, and PointerReleased events passed through by the InkPresenter. 所有的選取功能都是在這些事件的處理常式中實作的。All selection functionality is implemented in the handlers for these events.

    最後,會針對 InkPresenterStrokeStartedStrokesErased 事件指派接聽程式 。Finally, we assign listeners for the StrokeStarted and StrokesErased events of the InkPresenter. 如果開始新的筆劃或擦掉了現有的筆劃,我們就會使用這些事件的處理常式來清除 UI 選取項目。We use the handlers for these events to clean up the selection UI if a new stroke is started or an existing stroke is erased.

    含有預設黑色筆墨筆劃的 InkCanvas

      public MainPage()
      {
        this.InitializeComponent();
    
        // Set supported inking device types.
        inkCanvas.InkPresenter.InputDeviceTypes =
          Windows.UI.Core.CoreInputDeviceTypes.Mouse |
          Windows.UI.Core.CoreInputDeviceTypes.Pen;
    
        // Set initial ink stroke attributes.
        InkDrawingAttributes drawingAttributes = new InkDrawingAttributes();
        drawingAttributes.Color = Windows.UI.Colors.Black;
        drawingAttributes.IgnorePressure = false;
        drawingAttributes.FitToCurve = true;
        inkCanvas.InkPresenter.UpdateDefaultDrawingAttributes(drawingAttributes);
    
        // By default, the InkPresenter processes input modified by
        // a secondary affordance (pen barrel button, right mouse
        // button, or similar) as ink.
        // To pass through modified input to the app for custom processing
        // on the app UI thread instead of the background ink thread, set
        // InputProcessingConfiguration.RightDragAction to LeaveUnprocessed.
        inkCanvas.InkPresenter.InputProcessingConfiguration.RightDragAction =
            InkInputRightDragAction.LeaveUnprocessed;
    
        // Listen for unprocessed pointer events from modified input.
        // The input is used to provide selection functionality.
        inkCanvas.InkPresenter.UnprocessedInput.PointerPressed +=
            UnprocessedInput_PointerPressed;
        inkCanvas.InkPresenter.UnprocessedInput.PointerMoved +=
            UnprocessedInput_PointerMoved;
        inkCanvas.InkPresenter.UnprocessedInput.PointerReleased +=
            UnprocessedInput_PointerReleased;
    
        // Listen for new ink or erase strokes to clean up selection UI.
        inkCanvas.InkPresenter.StrokeInput.StrokeStarted +=
            StrokeInput_StrokeStarted;
        inkCanvas.InkPresenter.StrokesErased +=
            InkPresenter_StrokesErased;
      }
    
  4. 接著,會針對未處理的 PointerPressedPointerMovedPointerReleased 事件定義處理常式,這些事件是透過 InkPresenter 來傳入。We then define handlers for the unprocessed PointerPressed, PointerMoved, and PointerReleased events passed through by the InkPresenter.

    所有的選取功能都是在這些處理常式中實作的,包括套索筆劃和週框。All selection functionality is implemented in these handlers, including the lasso stroke and the bounding rectangle.

    選取套索

      // Handle unprocessed pointer events from modified input.
      // The input is used to provide selection functionality.
      // Selection UI is drawn on a canvas under the InkCanvas.
      private void UnprocessedInput_PointerPressed(
        InkUnprocessedInput sender, PointerEventArgs args)
      {
        // Initialize a selection lasso.
        lasso = new Polyline()
        {
            Stroke = new SolidColorBrush(Windows.UI.Colors.Blue),
            StrokeThickness = 1,
            StrokeDashArray = new DoubleCollection() { 5, 2 },
            };
    
            lasso.Points.Add(args.CurrentPoint.RawPosition);
    
            selectionCanvas.Children.Add(lasso);
        }
    
        private void UnprocessedInput_PointerMoved(
          InkUnprocessedInput sender, PointerEventArgs args)
        {
          // Add a point to the lasso Polyline object.
          lasso.Points.Add(args.CurrentPoint.RawPosition);
        }
    
        private void UnprocessedInput_PointerReleased(
          InkUnprocessedInput sender, PointerEventArgs args)
        {
          // Add the final point to the Polyline object and
          // select strokes within the lasso area.
          // Draw a bounding box on the selection canvas
          // around the selected ink strokes.
          lasso.Points.Add(args.CurrentPoint.RawPosition);
    
          boundingRect =
            inkCanvas.InkPresenter.StrokeContainer.SelectWithPolyLine(
              lasso.Points);
    
          DrawBoundingRect();
        }
    
  5. 為了推斷出 PointerReleased 事件處理常式,我們清除了所有內容的選取項目層級 (套索筆劃),然後在套索區域所圍繞的筆墨筆劃四周繪製單一週框。To conclude the PointerReleased event handler, we clear the selection layer of all content (the lasso stroke) and then draw a single bounding rectangle around the ink strokes encompassed by the lasso area.

    選取週框

      // Draw a bounding rectangle, on the selection canvas, encompassing
      // all ink strokes within the lasso area.
      private void DrawBoundingRect()
      {
        // Clear all existing content from the selection canvas.
        selectionCanvas.Children.Clear();
    
        // Draw a bounding rectangle only if there are ink strokes
        // within the lasso area.
        if (!((boundingRect.Width == 0) ||
          (boundingRect.Height == 0) ||
          boundingRect.IsEmpty))
          {
            var rectangle = new Rectangle()
            {
              Stroke = new SolidColorBrush(Windows.UI.Colors.Blue),
                StrokeThickness = 1,
                StrokeDashArray = new DoubleCollection() { 5, 2 },
                Width = boundingRect.Width,
                Height = boundingRect.Height
            };
    
            Canvas.SetLeft(rectangle, boundingRect.X);
            Canvas.SetTop(rectangle, boundingRect.Y);
    
            selectionCanvas.Children.Add(rectangle);
          }
        }
    
  6. 最後,會針對 StrokeStartedStrokesErased InkPresenter 事件定義處理常式。Finally, we define handlers for the StrokeStarted and StrokesErased InkPresenter events.

    每當偵測到新的筆劃時,這兩者只需要呼叫相同的清理函式來清除目前的選取範圍。These both just call the same cleanup function to clear the current selection whenever a new stroke is detected.

      // Handle new ink or erase strokes to clean up selection UI.
      private void StrokeInput_StrokeStarted(
        InkStrokeInput sender, Windows.UI.Core.PointerEventArgs args)
      {
        ClearSelection();
      }
    
      private void InkPresenter_StrokesErased(
        InkPresenter sender, InkStrokesErasedEventArgs args)
      {
        ClearSelection();
      }
    
  7. 以下這個函式會在開始新的筆劃或清除現有的筆劃時,從選取的畫布中移除所有 UI 選取項目。Here's the function to remove all selection UI from the selection canvas when a new stroke is started or an existing stroke is erased.

      // Clean up selection UI.
      private void ClearSelection()
      {
        var strokes = inkCanvas.InkPresenter.StrokeContainer.GetStrokes();
        foreach (var stroke in strokes)
        {
          stroke.Selected = false;
        }
        ClearDrawnBoundingRect();
       }
    
      private void ClearDrawnBoundingRect()
      {
        if (selectionCanvas.Children.Any())
        {
          selectionCanvas.Children.Clear();
          boundingRect = Rect.Empty;
        }
      }
    

轉譯自訂的筆跡Custom ink rendering

根據預設,筆墨輸入是在低延遲背景執行緒上處理,並在進行中轉譯,或在其繪製期間轉譯為「濕潤」狀態。By default, ink input is processed on a low-latency background thread and rendered in-progress, or "wet", as it is drawn. 完成筆劃 (拿起畫筆或手指,或是放開滑鼠按鈕) 時,即會在 UI 執行緒上處理該筆劃,並以「烘乾」狀態轉譯到 InkCanvas 層級 (在應用程式內容上方,並取代濕潤的筆墨)。When the stroke is completed (pen or finger lifted, or mouse button released), the stroke is processed on the UI thread and rendered "dry" to the InkCanvas layer (above the application content and replacing the wet ink).

您可以透過「自訂烘乾」濕潤的筆墨筆劃來覆寫此預設行為並完全控制筆跡體驗。You can override this default behavior and completely control the inking experience by "custom drying" the wet ink strokes. 雖然預設行為通常針對大部分的應用程式都已足夠,在某些案例下仍然可能會需要自訂烘乾,包括:While the default behavior is typically sufficient for most applications, there are a few cases where custom drying might be required, these include:

  • 更有效率的管理大型或複雜的筆墨筆劃集合More efficient management of large, or complex, collections of ink strokes
  • 在大型的筆跡畫布上支援的更有效率的平移和縮放More efficient panning and zooming support on large ink canvases
  • 間隔筆跡和其他物件,例如形狀或文字,同時維持 Z 的順序Interleaving ink and other objects, such as shapes or text, while maintaining z-order
  • 烘乾並同步將筆跡轉換成 DirectX 形狀 (例如,點陣化的直線或形狀,再整合到應用程式內容而非分離的 InkCanvas 層)。Drying and converting ink synchronously into a DirectX shape (for example, a straight line or shape rasterized and integrated into application content instead of as a separate InkCanvas layer).

自訂烘乾必須要有 IInkD2DRenderer 物件才能管理筆墨輸入,並將它轉譯到通用 Windows app 的 Direct2D 裝置內容,而不是預設的 InkCanvas 控制項。Custom drying requires an IInkD2DRenderer object to manage the ink input and render it to the Direct2D device context of your Universal Windows app, instead of the default InkCanvas control.

藉由呼叫 ActivateCustomDrying (在載入 InkCanvas 之前),app 會建立 InkSynchronizer 物件,來自訂如何將筆墨筆劃以烘乾狀態轉譯到 SurfaceImageSourceVirtualSurfaceImageSourceBy calling ActivateCustomDrying (before the InkCanvas is loaded), an app creates an InkSynchronizer object to customize how an ink stroke is rendered dry to a SurfaceImageSource or VirtualSurfaceImageSource.

SurfaceImageSourceVirtualSurfaceImageSource 都會為您的應用程式提供 DirectX 共用表面,可在其中繪製並寫入您應用程式的內容,但 VSIS 提供比螢幕更大的虛擬表面,可進行效能更高的平移和縮放。Both SurfaceImageSource and VirtualSurfaceImageSource provide a DirectX shared surface for your app to draw into and compose into your application's content, although VSIS provides a virtual surface that’s larger than the screen for performant panning and zooming. 因為這些表面的視覺更新都是與 XAML UI 執行緒同步的,當筆跡轉譯到其中之一時,濕潤的筆跡便可同時從 InkCanvas 移除。Because visual updates to these surfaces are synchronized with the XAML UI thread, when ink is rendered to either, the wet ink can be removed from the InkCanvas simultaneously.

您也可以將烘乾筆跡自訂成 SwapChainPanel,但此舉將無法保證與 UI 執行緒的同步,並且當筆跡轉譯到您的 SwapChainPanel 和筆跡從 InkCanvas 移除時將會產生延遲。You can also custom dry ink to a SwapChainPanel, but synchronization with the UI thread is not guaranteed and there might be a delay between when the ink is rendered to your SwapChainPanel and when ink is removed from the InkCanvas.

如需這項功能的完整範例,請參閱複雜的筆跡範例For a full example of this functionality, see the Complex ink sample.

注意

自訂乾燥與 InkToolbarCustom drying and the InkToolbar
如果您的 app 使用自訂的乾燥實作覆寫 InkPresenter 的預設筆跡轉譯行為,InkToolbar 就不會再有轉譯的筆墨筆觸,InkToolbar 的內建清除命令也無法如預期般運作。If your app overrides the default ink rendering behavior of the InkPresenter with a custom drying implementation, the rendered ink strokes are no longer available to the InkToolbar and the built-in erase commands of the InkToolbar do not work as expected. 若要提供清除功能,就必須處理所有指標事件、對每一個筆劃執行點擊測試,並且覆寫內建的「清除所有筆跡」命令。To provide erase functionality, you must handle all pointer events, perform hit-testing on each stroke, and override the built-in "Erase all ink" command.

主題Topic 描述Description
辨識筆墨筆劃Recognize ink strokes 使用手寫辨識,將筆墨筆劃轉換為文字,或者使用自訂辨識轉換為形狀。Convert ink strokes to text using handwriting recognition, or to shapes using custom recognition.
儲存和擷取筆墨筆劃Store and retrieve ink strokes 使用內嵌的筆跡序列化格式 (ISF) 中繼資料,在圖形交換格式 (GIF) 檔案中儲存筆墨筆劃資料。Store ink stroke data in a Graphics Interchange Format (GIF) file using embedded Ink Serialized Format (ISF) metadata.
InkToolbar 加入 UWP,筆跡應用程式Add an InkToolbar to a UWP inking app 將預設 InkToolbar 新增至通用 Windows 平台 (UWP) 手寫筆跡應用程式、將自訂的畫筆按鈕新增至 InkToolbar,以及將自訂的畫筆按鈕繫結到自訂的畫筆定義。Add a default InkToolbar to a Universal Windows Platform (UWP) inking app, add a custom pen button to the InkToolbar, and bind the custom pen button to a custom pen definition.

ApiAPIs

範例Samples

封存範例Archive Samples