Windows 앱의 펜 조작 및 Windows Ink

Hero image of the Surface Pen.
Surface 펜(Microsoft Store에서 구매 가능).

개요

Windows 앱을 펜 입력에 최적화하여 사용자에게 표준 포인터 디바이스 기능과 최적의 Windows Ink 환경을 제공하세요.

참고 항목

이 항목에서는 Windows Ink 플랫폼에 중점을 둡니다. 일반적인 포인터 입력 처리(마우스, 터치 및 터치 패드와 유사)는 포인터 입력 처리를 참조하세요.

Windows 앱에서 수동 입력 사용

Windows Pen 및 Windows Ink를 사용하여 보다 매력적인 엔터프라이즈 앱 빌드

Windows Ink 플랫폼은 펜 장치와 함께 디지털 필기 노트, 드로잉 및 주석을 만드는 자연스러운 방법을 제공합니다. 이 플랫폼은 디지타이저 입력을 잉크 데이터로 캡처하고, 잉크 데이터를 생성하고, 잉크 데이터를 관리하고, 출력 디바이스에서 잉크 스트로크로 렌더링하고, 필기 인식을 통해 잉크를 텍스트로 변환하도록 지원합니다.

사용자가 쓰거나 그릴 때 펜의 기본 위치와 움직임을 캡처하는 것 외에도 앱은 스트로크 전체에서 사용되는 다양한 양의 압력을 추적하고 수집할 수 있습니다. 이 정보는 펜 팁 모양, 크기 및 회전, 잉크 색 및 용도(일반 잉크, 지우기, 강조 표시 및 선택)에 대한 설정과 함께 펜, 연필 또는 브러시로 종이에 쓰거나 그리는 것과 매우 유사한 사용자 환경을 제공할 수 있습니다.

참고 항목

또한 앱은 터치 디지타이저 및 마우스 디바이스를 비롯한 다른 포인터 기반 디바이스의 잉크 입력을 지원할 수 있습니다. 

잉크 플랫폼은 매우 유연합니다. 요구 사항에 따라 다양한 수준의 기능을 지원하도록 설계되었습니다.

Windows Ink UX 지침은 Inking (수동 입력) 컨트롤을 참조하세요.

Windows Ink 플랫폼의 구성 요소

구성 요소 설명
InkCanvas 기본적으로 펜의 모든 입력을 잉크 스트로크 또는 지우기 스트로크로 수신하고 표시하는 XAML UI 플랫폼 컨트롤입니다.
InkCanvas를 사용하는 방법에 대한 자세한 내용은 Windows Ink 스트로크를 텍스트로 인식하고 Windows Ink 스트로크 데이터를 저장하고 검색하는 방법을 참조하세요.
InkPresenter InkCanvas 컨트롤과 함께 인스턴스화된 코드 숨김 개체입니다(InkCanvas.InkPresenter 속성을 통해 노출됨). 이 개체는 InkCanvas에서 노출하는 모든 기본 수동 입력 기능과 추가 사용자 지정 및 개인 설정을 위한 포괄적인 API 집합을 제공합니다.
InkPresenter를 사용하는 방법에 대한 자세한 내용은 Windows Ink 스트로크를 텍스트로 인식하고 Windows Ink 스트로크 데이터를 저장하고 검색하는 방법을 참조하세요.
InkToolbar XAML UI 플랫폼 컨트롤에는 연결된 InkCanvas에서 잉크 관련 기능을 활성화하는 사용자 지정 및 확장 가능한 단추 모음이 포함됩니다.
InkToolbar를 사용하는 방법은 Windows 앱 수동 입력 앱에 InkToolbar 추가를 참조하세요.
IInkD2DRenderer 기본 InkCanvas 컨트롤 대신 유니버설 Windows 앱의 지정된 Direct2D 디바이스 컨텍스트에 잉크 스트로크를 렌더링할 수 있습니다. 이렇게 하면 수동 입력 환경을 완전히 사용자 지정할 수 있습니다.
자세한 내용은 Complex ink sample을 참조하세요.

InkCanvas를 사용하는 기본 수동 입력

기본 수동 입력 기능을 추가하려면 앱의 적절한 페이지에 InkCanvas UWP 플랫폼 컨트롤을 배치합니다.

기본적으로 InkCanvas는 펜에서만 잉크 입력을 지원합니다. 입력은 색 및 두께에 대한 기본 설정(두께가 2픽셀인 검은색 볼펜)을 사용하여 잉크 스트로크로 렌더링되거나 스트로크 지우개(지우개 팁 또는 지우개 단추로 수정된 펜 팁에서 입력된 경우)로 처리됩니다.

참고 항목

지우개 팁 또는 단추가 없는 경우 펜 팁의 입력을 지우기 스트로크로 처리하도록 InkCanvas를 구성할 수 있습니다.

이 예제에서 InkCanvas는 배경 이미지를 오버레이합니다.

참고 항목

InkCanvas의 기본 HeightWidth 속성은 자녀 요소(예: StackPanel 또는 Grid 컨트롤)의 크기를 자동으로 설정하는 요소의 자식이 아닌 경우 0입니다.

<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 컨트롤에서 펜 입력을 렌더링하는 방법을 보여 줍니다.

Screenshot of the blank InkCanvas with a background image. Screenshot of the InkCanvas with ink strokes. Screenshot of the InkCanvas with one stroke erased.
배경 이미지가 있는 빈 InkCanvas입니다. 잉크 스트로크가 있는 InkCanvas입니다. 한 스트로크가 지워진 InkCanvas입니다(지우기는 부분이 아닌 전체 스트로크에서 작동하는 방식을 확인합니다).

InkCanvas 컨트롤에서 지원하는 수동 입력 기능은 InkPresenter라는 코드 숨김 개체에서 제공됩니다.

기본 수동 입력의 경우 InkPresenter에 대해 직접 염려할 필요가 없습니다. 그러나 InkCanvas에서 수동 입력 동작을 사용자 지정하고 구성하려면 해당 InkPresenter 개체에 액세스해야 합니다.

InkPresenter를 사용하여 기본 사용자 지정

InkPresenter 개체는 각 InkCanvas 컨트롤로 인스턴스화됩니다.

참고 항목

InkPresenter는 직접 인스턴스화할 수 없습니다. 대신 InkCanvasInkPresenter 속성을 통해 액세스합니다. 

해당 InkCanvas 컨트롤의 모든 기본 잉크 입력 동작을 제공할 뿐만 아니라, InkPresenter는 추가 스트로크 사용자 지정 및 세분화된 펜 입력 관리(표준 및 수정된)를 위한 포괄적인 API 집합을 제공합니다. 여기에는 스트로크 속성, 지원되는 입력 디바이스 유형, 입력을 개체에서 처리하는지 아니면 앱으로 보내서 처리하는지 여부가 포함됩니다.

참고 항목

표준 잉크 입력(펜 팁 또는 지우개 팁/단추의)은 펜 배럴 단추, 마우스 오른쪽 단추 또는 유사한 메커니즘과 같은 보조 하드웨어 어포던스를 사용하여 수정되지 않습니다.

기본적으로 잉크는 펜 입력에만 지원됩니다. 여기서는 펜과 마우스의 입력 데이터를 잉크 스트로크로 해석하도록 InkPresenter를 구성합니다. 또한 스트로크를 InkCanvas로 렌더링하는 데 사용되는 몇 가지 초기 잉크 스트로크 특성을 설정합니다.

마우스와 터치 수동 입력을 사용하도록 설정하려면 InkPresenterInputDeviceTypes 속성을 원하는 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에서 펜 입력을 처리하고 사용자 지정하는 방법을 보여 줍니다.

Screenshot that shows the InkCanvas with default black ink strokes.

기본 검은색 잉크 스트로크가 있는 InkCanvas입니다.

Screenshot of the InkCanvas with user selected red ink strokes.

사용자가 빨간색 잉크 스트로크를 선택한 InkCanvas입니다.

스트로크 선택과 같이 수동 입력 및 지우기 이외의 기능을 제공하려면 앱이 처리되지 않은 앱을 통과하도록 InkPresenter에 대한 특정 입력을 식별해야 합니다.

고급 처리를 위한 통과 입력

기본적으로 InkPresenter는 펜 배럴 단추, 오른쪽 마우스 단추 등의 보조 하드웨어 어포던스에 의해 수정되는 입력을 포함하여 모든 입력을 잉크 스트로크 또는 지우기 스트로크로 처리합니다. 그러나 사용자는 일반적으로 이러한 보조 어포던스의 사용으로 일부 추가 기능이나 수정된 동작을 기대합니다.

일부 경우 사용자의 앱 UI 선택에 따라 보조 어포던스가 없는 펜을 위한 추가 기능(보통 펜 팁과 관련되지 않은 기능), 다른 입력 디바이스 유형 또는 일부 수정된 동작 유형을 지원해야 할 수 있습니다.

이를 지원하기 위해 특정 입력을 처리되지 않은 상태로 두도록 InkPresenter를 구성할 수 있습니다. 처리되지 않은 이 입력은 처리를 위해 앱으로 전달됩니다.

예제 - 처리되지 않은 입력을 사용하여 스트로크 선택 구현

Windows Ink 플랫폼에서는 스트로크 선택과 같은 수정된 입력을 요구하는 기본 지원 작업을 제공하지 않습니다. 이러한 기능을 지원하려면 앱에 사용자 지정 솔루션을 제공해야 합니다.

다음은 펜 배럴 단추(또는 마우스 오른쪽 단추)를 사용하여 입력을 수정할 때 스트로크 선택을 활성화하는 방법을 보여주는 코드 예입니다(전체 코드는 MainPage.xaml 및 MainPage.xaml.cs 파일에 있음).

  1. 먼저 MainPage.xaml에서 UI를 설정합니다.

    여기서는 선택 스트로크를 그리기 위해 캔버스(InkCanvas 아래)를 추가합니다. 별도의 레이어를 사용하여 선택 스트로크를 그리면 InkCanvas 및 해당 콘텐츠가 그대로 유지됩니다.

    Screenshot of the blank InkCanvas with an underlying selection canvas.

      <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의 측면에 대한 참조를 유지하기 위해 몇 가지 전역 변수를 선언합니다. 특히 선택한 올가미 스트로크와 선택한 스트로크를 강조 표시하는 경계 사각형입니다.

      // Stroke selection tool.
      private Polyline lasso;
      // Stroke selection area.
      private Rect boundingRect;
    
  3. 다음으로 펜과 마우스의 입력 데이터를 잉크 스트로크로 해석하도록 InkPresenter를 구성하고 스트로크를 InkCanvas로 렌더링하는 데 사용되는 몇 가지 초기 잉크 스트로크 특성을 설정합니다.

    가장 중요한 것은 InkPresenterInputProcessingConfiguration 속성을 사용하여 수정된 입력이 앱을 통해 처리되어야 함을 나타내는 것입니다. 수정된 입력은 InputProcessingConfiguration.RightDragAction 값을 InkInputRightDragAction.LeaveUnprocessed 값으로 할당하여 지정합니다. 이 값이 설정되면 InkPresenterInkUnprocessedInput 클래스(처리할 포인터 이벤트 집합)로 전달됩니다.

    InkPresenter에 의해 전달된 처리되지 않은 PointerPressed, PointerMovedPointerReleased 이벤트에 대한 수신기를 할당합니다. 모든 선택 기능은 이러한 이벤트에 대한 처리기에서 구현됩니다.

    마지막으로 InkPresenterStrokeStartedStrokesErased 이벤트에 대한 수신기를 할당합니다. 이러한 이벤트에 대한 처리기를 사용하여 새 스트로크가 시작되거나 기존 스트로크가 지워지면 선택 UI를 정리합니다.

    Screenshot of the Advances ink customization sample app showing the inkcanvas with default black ink strokes.

      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. 그런 다음 InkPresenter에서 전달한 처리되지 않은 PointerPressed, PointerMoved, 및 PointerReleased 이벤트에 대한 처리기를 정의합니다.

    올가미 스트로크 및 경계 사각형을 포함하여 이러한 처리기에서 모든 선택 기능이 구현됩니다.

    Screenshot of the selection lasso.

      // 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 이벤트 처리기를 마무리하기 위해 모든 콘텐츠의 선택 계층(올가미 스트로크)을 지운 다음 올가미 영역이 포괄하는 잉크 스트로크 주위에 단일 경계 사각형을 그립니다.

    Screenshot of the selection bounding rect.

      // 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 이벤트에 대한 처리기를 정의합니다.

    둘 다 동일한 정리 함수를 호출하여 새 스트로크가 검색될 때마다 현재 선택을 지웁니다.

      // 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를 제거하는 함수입니다.

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

잉크 렌더링 사용자 지정

기본적으로 잉크 입력은 짧은 대기 시간의 백그라운드 스레드에서 처리되고 그릴 때 진행 중 또는 "젖은" 상태로 렌더링됩니다. 스트로크가 완료되면(펜 또는 손가락을 떼거나 마우스 단추를 놓으면) 스트로크가 UI 스레드에서 처리되고 InkCanvas 계층(애플리케이션 콘텐츠 위 및 젖은 잉크 교체)에 "건조"하게 렌더링됩니다.

젖은 잉크 스트로크를 "사용자 지정 건조"함으로써 이러한 기본 동작을 재정의하고 잉크 입력 환경을 완전히 제어할 수 있습니다. 일반적으로 대부분의 애플리케이션에서는 기본 동작으로도 충분하지만, 다음과 같이 사용자 지정 건조가 필요할 수 있는 경우가 몇 가지 있습니다.

  • 대용량이거나 복잡한 잉크 스트로크 컬렉션의 보다 효율적인 관리
  • 넓은 잉크 캔버스에서의 보다 효율적인 이동 및 확대/축소 지원
  • z-순서를 유지 관리하면서 잉크 및 도형이나 텍스트와 같은 기타 개체 인터리빙
  • DirectX 셰이프로 잉크를 동기적으로 건조하고 변환(예: 별도의 InkCanvas 레이어 형식이 아닌 애플리케이션 콘텐츠로 직선이나 도형을 레스터화하고 통합).

사용자 지정 건조를 사용하려면 IInkD2DRenderer 개체가 잉크 입력을 관리하고 기본 InkCanvas 컨트롤 대신 유니버설 Windows 앱의 Direct2D 디바이스 컨텍스트로 렌더링해야 합니다.

InkCanvas가 로드되기 전에 ActivateCustomDrying을 호출하여 잉크 스트로크가 SurfaceImageSource 또는 VirtualSurfaceImageSource에 건조하게 렌더링되는 방식을 사용자 지정하는 InkSynchronizer 개체를 만듭니다.

VSIS는 고성능의 이동 및 확대/축소를 위해 화면보다 큰 가상 표면을 제공하는 반면, SurfaceImageSourceVirtualSurfaceImageSource는 모두 앱에서 애플리케이션의 콘텐츠에 그림을 그리고 글을 작성하도록 DirectX 공유 표면을 제공합니다. 이러한 표면에 대한 시작적 업데이트는 XAML UI 스레드와 동기화되므로 잉크가 둘 중 하나로 렌더링되면 젖은 잉크가 InkCanvas에서 동시에 제거됩니다.

건조 잉크를 SwapChainPanel로 사용자 지정할 수도 있지만, UI 스레드와의 동기화는 보장되지 않으며 잉크가 SwapChainPanel에 렌더링되는 시기와 잉크가 InkCanvas에서 제거되는 시기 간에 지연이 발생할 수 있습니다.

이 기능의 전체 예제는 복합 잉크 샘플을 참조하세요.

참고 항목

사용자 지정 건조 및 InkToolbar
앱이 사용자 지정 건조 구현을 사용하여 InkPresenter의 기본 잉크 렌더링 동작을 재정의하는 경우 렌더링된 잉크 스트로크는 더 이상 InkToolbar에서 사용할 수 없으며 InkToolbar의 기본 제공 지우기 명령은 예상대로 작동하지 않습니다. 지우기 기능을 제공하려면 모든 포인터 이벤트를 처리하고, 각 스트로크에서 적중 테스트를 수행하고, 기본 제공 "모든 잉크 지우기" 명령을 재정의해야 합니다.

항목 설명
잉크 스트로크 인식 필기 인식을 사용하여 잉크 스트로크를 텍스트로 변환하거나 사용자 지정 인식을 사용하여 도형으로 변환합니다.
잉크 스트로크 저장 및 검색 포함된 ISF(Ink Serialized Format) 메타데이터를 사용하여 잉크 스트로크 데이터를 GIF(그래픽 교환 형식) 파일에 저장합니다.
Windows 수동 입력 앱에 InkToolbar 추가 Windows 앱 수동 입력 앱에 기본 InkToolbar를 추가하고, InkToolbar에 사용자 지정 펜 단추를 추가하고, 사용자 지정 펜 정의에 사용자 지정 펜 단추를 바인딩합니다.

API

샘플

보관 샘플