Поделиться через


Взаимодействие с пером и Windows Ink в приложениях Windows

изображение героя пера Surface.
Ручка Surface (доступна для покупки в Microsoft Store).

Обзор

Оптимизируйте приложение Windows для ввода пера, чтобы обеспечить как стандартные указателя устройства функциональные возможности, так и лучшие возможности Windows Ink для пользователей.

Замечание

В этом разделе рассматривается платформа Windows Ink. Для управления вводом указателя (аналогично мыши, сенсору и сенсорной панели) см. в .

Использование чернил в приложении для Windows

Использовать перо и рукописный ввод Windows для создания более увлекательных корпоративных приложений

Платформа Windows Ink вместе с устройством пера предоставляет естественный способ создания цифровых рукописных заметок, рисунков и заметок. Платформа поддерживает запись входных данных дигитайзера в виде рукописных данных, создания рукописных данных, управления данными рукописного ввода, отрисовки рукописных данных в виде росчерков рукописного ввода на выходном устройстве и преобразования рукописного ввода в текст с помощью распознавания рукописного ввода.

Помимо фиксации основного положения и движения пера во время письма или рисования, ваше приложение также может отслеживать и собирать различные уровни давления, используемого на протяжении штриха. Эта информация, а также параметры формы остриья пера, размера и поворота, цвет чернил и назначение (обычные чернила, стирание, выделение и выбор), позволяют предоставлять пользователям возможности, которые очень похожи на письмо или рисование на бумаге с пером, карандашом или кистью.

Замечание

Ваше приложение также может поддерживать ввод рукописного ввода с других устройств на основе указателя, включая сенсорные дигитайзеры и устройства мыши. 

Платформа рукописного ввода очень гибкая. Он предназначен для поддержки различных уровней функциональности в зависимости от ваших требований.

Для рекомендаций по UX интерфейсу Windows Ink см. раздел элементы управления рукописью.

Компоненты платформы Windows Ink

Компонент Описание
InkCanvas Элемент управления платформой пользовательского интерфейса XAML, который по умолчанию получает и отображает все входные данные из пера в виде росчерка рукописного ввода или штриха удаления.
Дополнительные сведения об использовании InkCanvas см. в разделе Распознавание росчерков Windows Ink как текст и Сохранение и получение данных росчерка Windows Ink.
InkPresenter Объект кода, созданный вместе с элементом управления InkCanvas (доступен через свойство InkCanvas.InkPresenter). Этот объект предоставляет все функции рукописного ввода по умолчанию, предоставляемые InkCanvas, а также комплексный набор API для дополнительной настройки и персонализации.
Дополнительные сведения об использовании InkPresenter см. в статье Распознавание штрихов Windows Ink как текста и Сохранение и извлечение данных штрихов Windows Ink.
InkToolbar Элемент управления платформы XAML UI, содержащий настраиваемую и расширяемую коллекцию кнопок, которые активируют функции рукописного ввода в связанном InkCanvas.
Дополнительные сведения об использовании InkToolbar см. в статье Добавление InkToolbar в приложение для рукописного ввода в Windows.
IInkD2DRenderer Включает отрисовку штрихов пера в заданный контекст устройства Direct2D универсального приложения Windows, а не элемента управления InkCanvas по умолчанию. Это обеспечивает полную настройку интерфейса рукописного ввода.
Для получения дополнительной информации см. образец сложных чернил .

Базовый ввод рукописи с помощью InkCanvas

Чтобы добавить основные функции рукописного ввода, просто поместите InkCanvas элемент управления платформой UWP на соответствующей странице в приложении.

По умолчанию InkCanvas поддерживает ввод только с помощью пера. Входные данные могут отображаться в виде росчерка рукописного ввода с использованием настроек по умолчанию для цвета и толщины (черной шариковой ручки толщиной 2 пикселя) или интерпретироваться как стирание (если данные поступают с наконечника ластика или если кончик пера изменен кнопкой стирания).

Замечание

Если наконечник или кнопка ластика отсутствует, InkCanvas можно настроить на обработку входных данных с кончика пера как стертый штрих.

В этом примере InkCanvas накладывается на фоновое изображение.

Замечание

InkCanvas по умолчанию имеет свойства Height и Width, равные нулю, если он не является дочерним элементом элемента, который автоматически изменяет размер его дочерних элементов, например, элемента управления StackPanel или элемента управления Grid.

<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.

Снимок экрана: пустой объект InkCanvas с фоновым изображением. снимок экрана InkCanvas с росчерками рукописного ввода. снимок экрана InkCanvas с одним стиранием.
Пустой InkCanvas с фоновым изображением. Холст для чернил с рукописными росчерками. InkCanvas одним касанием стерся (обратите внимание, как удаление работает со всей линией, а не с её частью).

Функции рукописного ввода, поддерживаемые элементом управления InkCanvas, предоставляются объектом кода, который называется InkPresenter.

Для базовой работы с чернилами вам не нужно беспокоиться о InkPresenter. Однако для кастомизации и настройки поведения рукописного ввода в InkCanvasнеобходимо получить доступ к соответствующему объекту InkPresenter.

Базовая настройка с помощью InkPresenter

Объект InkPresenter создается с каждым элементом управления InkCanvas.

Замечание

Нельзя напрямую создать экземпляр InkPresenter. Вместо этого доступ осуществляется через свойство InkPresenter объекта InkCanvas

Помимо предоставления всех действий рукописного ввода по умолчанию соответствующего элемента управления InkCanvas, InkPresenter предоставляет полный набор API для дополнительной настройки штрихов и более точного управления входными данными пера (стандартным и измененным). Сюда входят свойства штриха, поддерживаемые типы устройств ввода и то, обрабатываются ли входные данные непосредственно объектом или передаются в приложение для обработки.

Замечание

Стандартный ввод рукописного текста (с кончика пера или кнопки ластика) не изменяется при использовании дополнительного аппаратного средства, например кнопки на стержне пера, правой кнопки мыши или аналогичного механизма.

По умолчанию поддержка чернил предоставляется только для ввода с помощью стилуса. Здесь мы настраиваем InkPresenter для интерпретации входных данных как росчерков от пера и мыши. Мы также устанавливаем некоторые начальные атрибуты чернильного штриха, используемые для отрисовки штрихов на InkCanvas .

Чтобы включить черчение с помощью мыши и сенсорного ввода, задайте свойство InputDeviceTypes объекта InkPresenter на комбинацию значений CoreInputDeviceTypes, которую вы хотите использовать.

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);
}

Атрибуты росчерка рукописного ввода можно задать динамически для удовлетворения требований пользователей или приложений.

Здесь мы позволим пользователю выбрать из списка цветов рукописного ввода.

<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>

Затем мы обрабатываем изменения выбранного цвета и обновляем атрибуты штриха соответствующим образом.

// 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.

Снимок экрана, показывающий по умолчанию черные штрихи на InkCanvas.

InkCanvas с черными штрихами чернил по умолчанию.

Скриншот InkCanvas с выбранными пользователем красными штрихами.

InkCanvas с выбранными пользователем красными штрихами.

Чтобы обеспечить функциональные возможности за пределами рукописного ввода и удаления, таких как выбор штриха, приложение должно определить определенные входные данные для InkPresenter для передачи без обработки приложения.

Сквозные входные данные для расширенной обработки

По умолчанию InkPresenter обрабатывает все входные данные как росчерк рукописного ввода или штрих удаления, включая входные данные, измененные дополнительным оборудованием, например кнопку пера, правую кнопку мыши или аналогичную. Однако обычно пользователи ожидают некоторые дополнительные функциональные возможности или измененное поведение с этими дополнительными разрешениями.

В некоторых случаях может потребоваться предоставить дополнительные функции для перьев без вторичных возможностей (функции, которые обычно не ассоциируются с наконечником пера), другие типы входных устройств или определенные типы измененного поведения на основе выбора пользователя в пользовательском интерфейсе вашего приложения.

Для поддержки этого можно настроить InkPresenter , чтобы оставить определенные входные данные без обработки. Затем эти необработанные входные данные передаются в приложение для обработки.

Пример - Использование необработанных входных данных для реализации выбора штрихов

Платформа Windows Ink не предоставляет встроенную поддержку действий, требующих измененных входных данных, таких как выбор штриха. Для поддержки таких функций необходимо предоставить пользовательское решение в приложениях.

Следующий пример кода (весь код находится в файлах MainPage.xaml и MainPage.xaml.cs) показывает поэтапно, как включить выделение штрихов при изменении входных данных с помощью боковой кнопки пера (или правой кнопки мыши).

  1. Сначала мы настраиваем пользовательский интерфейс в MainPage.xaml.

    Здесь мы добавляем холст (под InkCanvas) для того, чтобы нарисовать штрих выделения. Использование отдельного слоя для рисования штриха выделения оставляет нетронутыми InkCanvas и его содержимое.

    Снимок экрана пустого 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 мы объявляем несколько глобальных переменных для хранения ссылок на аспекты пользовательского интерфейса выбора. В частности, штрих выделения лассо и ограничивающий прямоугольник, который выделяет выбранные штрихи.

      // Stroke selection tool.
      private Polyline lasso;
      // Stroke selection area.
      private Rect boundingRect;
    
  3. Затем мы настроим InkPresenter для интерпретации входных данных из пера и мыши как рукописных штрихов и задаем некоторые начальные атрибуты рукописного штриха, используемые для отрисовки штрихов на InkCanvas.

    Самое главное, мы используем свойство InputProcessingConfigurationInkPresenter, чтобы указать, что любые измененные входные данные должны обрабатываться приложением. Измененный ввод задается путем присвоения InputProcessingConfiguration.RightDragAction значения InkInputRightDragAction.LeaveUnprocessed. Если это значение задано, InkPresenter переходит в класс InkUnprocessedInput, предоставляя набор событий указателя для вашей обработки.

    Мы назначаем прослушиватели для необработанных событий PointerPressed, PointerMovedи PointerReleased, которые проходят через InkPresenter. Все функции выбора реализованы в обработчиках этих событий.

    Наконец, мы назначаем прослушивателей для событий StrokeStarted и StrokesErasedInkPresenter. Обработчики этих событий используются для очистки пользовательского интерфейса выбора при запуске нового штриха или удалении существующего штриха.

    Снимок экрана приложения-примера настройки чернил, показывающий холст для чернил с черными росчерками по умолчанию.

      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. Затем мы определяем обработчики для необработанных PointerPressed, PointerMovedи PointerReleased событий, передаваемых с помощью InkPresenter.

    Все функции выбора реализованы в этих обработчиках, включая штрих лассо и ограничивающий прямоугольник.

    снимок экрана инструмента выделения лассо.

      // 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, мы очищаем слой выбора всего содержимого (штрих лассо), а затем рисуем один ограничивающий прямоугольник вокруг росчерков рукописного ввода, охватываемых областью лассо.

    снимок экрана с границей выделения прямоугольника.

      // 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. Наконец, мы определим обработчики событий InkPresenter для StrokeStarted и StrokesErased.

    Эти оба просто вызывают одну и ту же функцию очистки, чтобы очистить текущий выбор всякий раз при обнаружении нового штриха.

      // 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. Вот функция, чтобы удалить весь интерфейс выделения из холста выбора, когда начинается новый росчерк или удаляется существующий штрих.

      // 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;
        }
      }
    

Настраиваемый рендеринг чернил

По умолчанию рукописный ввод обрабатывается в фоновом потоке с низкой задержкой и отображается в процессе рисования, в "мокром" состоянии. После завершения росчерка (перо или палец оторваны, или кнопка мыши отпущена), штрих обрабатывается в потоке пользовательского интерфейса и отрисовывается "сухим" на слой InkCanvas (над содержимым приложения, заменяя мокрое перо).

Это поведение по умолчанию можно переопределить и полностью управлять процессом рукописного ввода, произвольно суша мокрые штрихи. Хотя поведение по умолчанию обычно достаточно для большинства приложений, существует несколько случаев, когда может потребоваться настраиваемая сушка, к ним относятся:

  • Более эффективное управление большими или сложными коллекциями рукописных росчерков
  • Более эффективная поддержка перемещения и масштабирования на больших холстах для рукописного ввода
  • Чередование рукописного ввода и других объектов, таких как фигуры или текст, при сохранении Z-порядка.
  • Сушка и преобразование рукописного ввода в фигуру DirectX (например, прямая линия или фигура, растровизированы и интегрированы в содержимое приложения вместо отдельного слоя InkCanvas).

Для пользовательской сушки требуется объект IInkD2DRenderer для управления вводом рукописного ввода и визуализации его в контексте устройства Direct2D универсального приложения Windows вместо элемента управления InkCanvas.

Вызвав ActivateCustomDrying (до загрузки InkCanvas), приложение создает объект InkSynchronizer для настройки того, как росчерк рукописного ввода высушивается и отображается в SurfaceImageSource или VirtualSurfaceImageSource.

Как SurfaceImageSource, так и VirtualSurfaceImageSource предоставляют общую поверхность DirectX для отрисовки и компоновки содержимого вашего приложения, хотя VSIS предоставляет виртуальную поверхность, размер которой превышает экран, для эффективного панорамирования и масштабирования. Поскольку визуальные обновления этих поверхностей синхронизированы с потоком пользовательского интерфейса XAML, при отрисовке чернил на любой из них влажные чернила могут быть удалены из InkCanvas одновременно.

Вы также можете настроить высушивание чернил на SwapChainPanel, но синхронизация с потоком пользовательского интерфейса не гарантируется, и может возникнуть задержка между моментом, когда чернила отображаются на вашем SwapChainPanel, и моментом, когда они удаляются из InkCanvas.

Полный пример этой функции см. в сложном образце чернил .

Замечание

Настраиваемая сушка и InkToolbar
Если ваше приложение переопределяет поведение отрисовки рукописного ввода по умолчанию InkPresenter с помощью пользовательской реализации сушки, то отрисованные росчерки рукописного ввода больше не доступны для панели InkToolbar, и встроенные команды удаления InkToolbar не работают должным образом. Чтобы обеспечить функциональность удаления, необходимо обрабатывать все события указателя, выполнять проверку попадания на каждом штрихе и переопределять встроенную команду "Удалить всю рукопись".

Тема Описание
Распознавать рукописные росчерки Преобразование рукописных росчерков в текст с помощью распознавания рукописного ввода или фигур с помощью пользовательского распознавания.
Сохранение и извлечение штрихов рукописного ввода Храните данные штрихов рукописного ввода в файле формата обмена графикой (GIF) с использованием встроенных метаданных формата ISF (Ink Serialized Format).
Добавление панели рукописного ввода в приложение Windows для рукописного ввода Добавьте панель InkToolbar по умолчанию в приложение Windows для рукописного ввода, добавьте настраиваемую кнопку пера в панель InkToolbar и привяжите её к пользовательскому определению пера.

Программные интерфейсы

Образцы

Архивные примеры