Udostępnij przez


Dodawanie narzędzia InkToolbar do aplikacji systemu Windows

Istnieją dwie różne kontrolki, które ułatwiają pisanie odręczne w aplikacjach systemu Windows: InkCanvas i InkToolbar.

Kontrolka InkCanvas zapewnia podstawową funkcjonalność Windows Ink. Służy do renderowania wejścia pióra jako pociągnięcia atramentowego (przy użyciu ustawień domyślnych dla koloru i grubości) lub pociągnięcia wymazywania.

Aby uzyskać szczegółowe informacje o implementacji rozwiązania InkCanvas, zobacz Interakcje piórem i rysikiem w aplikacjach systemu Windows.

Jako całkowicie przezroczysta nakładka InkCanvas nie udostępnia żadnego wbudowanego interfejsu użytkownika do ustawiania właściwości pociągnięcia tuszem. Jeśli chcesz zmienić domyślne doświadczenie odręcznego pisania, pozwól użytkownikom ustawić właściwości pociągnięcia i umożliwić korzystanie z innych niestandardowych funkcji pisma odręcznego, masz dwie opcje:

  • W kodzie użyj bazowego obiektu InkPresenter powiązanego z InkCanvas.

    Interfejsy API InkPresenter obsługują rozbudowane dostosowywanie doświadczenia pisma odręcznego. Aby uzyskać więcej informacji, zobacz Interakcje piórem i rysikiem w aplikacjach systemu Windows.

  • Powiąż InkToolbar z InkCanvas. Domyślnie narzędzie InkToolbar udostępnia dostosowywalną i rozszerzalną kolekcję przycisków do aktywowania funkcji związanych z atramentem, takich jak rozmiar pociągnięcia, kolor pisma odpiętego i końcówka pióra.

    W tym temacie omówiono narzędzie InkToolbar.

Ważne interfejsy API: klasa InkCanvas, klasa InkToolbar, klasa InkPresenter, Windows.UI.Input.Inking

Domyślny pasek narzędzi do rysowania

Domyślnie pasek InkToolbar zawiera przyciski do rysowania, wymazywania, wyróżniania i wyświetlania szablonu (linijki lub kątomierza). W zależności od funkcji, inne ustawienia i polecenia, takie jak kolor tuszu, grubość pociągnięcia i wymazywanie całego tuszu, są udostępniane w oknie wysuwanym.

Narzędzie InkToolbar
Domyślny pasek narzędzi Windows Ink

Aby dodać domyślny InkToolbar do aplikacji do rysowania, wystarczy umieścić go na tej samej stronie co InkCanvas i skojarzyć te dwie kontrolki.

  1. W pliku MainPage.xaml zadeklaruj obiekt kontenera (na przykład używamy kontrolki Grid) dla powierzchni pisma odręcznego.
  2. Zadeklaruj obiekt InkCanvas jako podrzędny element kontenera. (Rozmiar InkCanvas jest dziedziczony od kontenera).
  3. Zadeklaruj element InkToolbar i użyj atrybutu TargetInkCanvas, aby powiązać go z inkCanvas.

Uwaga / Notatka

Upewnij się, że InkToolbar jest zadeklarowany po InkCanvas. Jeśli nie, nakładka InkCanvas uniemożliwia dostęp do paska narzędzi InkToolbar.

<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" />
        <InkToolbar x:Name="inkToolbar"
          VerticalAlignment="Top"
          TargetInkCanvas="{x:Bind inkCanvas}" />
    </Grid>
</Grid>

Dostosowywanie podstawowe

W tej sekcji omówiono niektóre podstawowe scenariusze dostosowywania paska narzędzi Windows Ink.

Określanie lokalizacji i orientacji

Po dodaniu paska narzędzi atramentu do aplikacji możesz zaakceptować domyślną lokalizację i orientację paska narzędzi lub ustawić je zgodnie z wymaganiami aplikacji lub użytkownika.

XAML

Jawnie określ lokalizację i orientację paska narzędzi za pomocą właściwości VerticalAlignment, HorizontalAlignment i Orientation .

Default Jawnie
Domyślna lokalizacja i orientacja paska narzędzi atramentu Wyraźna lokalizacja i orientacja paska narzędziowego atramentu
Domyślne położenie i orientacja paska narzędzi Windows Ink Określona lokalizacja i orientacja paska narzędzi Windows Ink

Oto kod do jawnego ustawiania lokalizacji i orientacji paska narzędzi atramentu w XAML.

<InkToolbar x:Name="inkToolbar" 
    VerticalAlignment="Center" 
    HorizontalAlignment="Right" 
    Orientation="Vertical" 
    TargetInkCanvas="{x:Bind inkCanvas}" />

Inicjowanie na podstawie preferencji użytkownika lub stanu urządzenia

W niektórych przypadkach możesz ustawić lokalizację i orientację paska narzędzi atramentu na podstawie preferencji użytkownika lub stanu urządzenia. W poniższym przykładzie pokazano, jak ustawić pozycję i orientację paska narzędzi atramentu na podstawie preferencji dotyczących pisania lewą lub prawą ręką określonych w Ustawienia > Urządzenia > Pióro i atrament systemu Windows > Pióro > Wybierz, z którą ręką piszesz.

Ustawienie dominującej ręki
Ustawienie dominującej ręki

Można odczytać to ustawienie za pomocą właściwości HandPreference elementu Windows.UI.ViewManagement i ustawić HorizontalAlignment na podstawie zwróconej wartości. W tym przykładzie umieszczamy pasek narzędzi po lewej stronie aplikacji dla leworęcznej osoby i po prawej stronie dla praworęcznej osoby.

Pobierz ten przykład z lokalizacji i orientacji paska narzędzi Ink (wersja podstawowa)

public MainPage()
{
    this.InitializeComponent();

    Windows.UI.ViewManagement.UISettings settings = 
        new Windows.UI.ViewManagement.UISettings();
    HorizontalAlignment alignment = 
        (settings.HandPreference == 
            Windows.UI.ViewManagement.HandPreference.LeftHanded) ? 
            HorizontalAlignment.Left : HorizontalAlignment.Right;
    inkToolbar.HorizontalAlignment = alignment;
}

Dynamiczne dostosowywanie stanu użytkownika lub urządzenia

Można również użyć powiązania, aby dbać o aktualizacje interfejsu użytkownika na podstawie zmian preferencji użytkownika, ustawień urządzenia lub stanów urządzeń. W poniższym przykładzie rozszerzamy poprzedni przykład i pokazujemy, jak dynamicznie ustawić pasek narzędzi atramentu na podstawie orientacji urządzenia, używając powiązania, obiektu ViewModel i interfejsu INotifyPropertyChanged.

Pobierz ten przykład z przykładowej lokalizacji i orientacji paska narzędzi pisania odręcznego (dynamiczny)

  1. Najpierw dodajmy nasz ViewModel.

    1. Dodaj nowy folder do projektu i wywołaj go ViewModels.

    2. Dodaj nową klasę do folderu ViewModels (na potrzeby tego przykładu nazwaliśmy ją InkToolbarSnippetHostViewModel.cs).

      Uwaga / Notatka

      Użyliśmy wzorca Singleton , ponieważ do życia aplikacji potrzebujemy tylko jednego obiektu tego typu

    3. Dodaj using System.ComponentModel przestrzeń nazw do pliku.

    4. Dodaj statyczną zmienną członkowską o nazwie instancja i statyczną właściwość do odczytu o nazwie Instancja. Ustaw konstruktor jako prywatny, aby upewnić się, że ta klasa będzie dostępna tylko za pośrednictwem właściwości Instance.

      Uwaga / Notatka

      Ta klasa dziedziczy interfejs INotifyPropertyChanged, który jest używany do powiadamiania klientów, zazwyczaj klientów powiązanych, że wartość właściwości zmieniła się. Użyjemy tej funkcji do obsługi zmian orientacji urządzenia (rozszerzymy ten kod i wyjaśnimy to w późniejszym kroku).

      using System.ComponentModel;
      
      namespace locationandorientation.ViewModels
      {
          public class InkToolbarSnippetHostViewModel : INotifyPropertyChanged
          {
              private static InkToolbarSnippetHostViewModel instance;
      
              public static InkToolbarSnippetHostViewModel Instance
              {
                  get
                  {
                      if (null == instance)
                      {
                          instance = new InkToolbarSnippetHostViewModel();
                      }
                      return instance;
                  }
              }
          }
      
          private InkToolbarSnippetHostViewModel() { }
      }
      
    5. Dodaj dwie właściwości logiczne do klasy InkToolbarSnippetHostViewModel: LeftHandedLayout (ta sama funkcja co poprzedni przykład XAML) i PortraitLayout (orientacja urządzenia).

      Uwaga / Notatka

      Właściwość PortraitLayout jest ustawiana i zawiera definicję zdarzenia PropertyChanged .

      public bool LeftHandedLayout
      {
          get
          {
              bool leftHandedLayout = false;
              Windows.UI.ViewManagement.UISettings settings =
                  new Windows.UI.ViewManagement.UISettings();
              leftHandedLayout = (settings.HandPreference ==
                  Windows.UI.ViewManagement.HandPreference.LeftHanded);
              return leftHandedLayout;
          }
      }
      
      public bool portraitLayout = false;
      public bool PortraitLayout
      {
          get
          {
              Windows.UI.ViewManagement.ApplicationViewOrientation winOrientation = 
                  Windows.UI.ViewManagement.ApplicationView.GetForCurrentView().Orientation;
              portraitLayout = 
                  (winOrientation == 
                      Windows.UI.ViewManagement.ApplicationViewOrientation.Portrait);
              return portraitLayout;
          }
          set
          {
              if (value.Equals(portraitLayout)) return;
              portraitLayout = value;
              PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("PortraitLayout"));
          }
      }
      
  2. Teraz dodajmy kilka klas konwerterów do naszego projektu. Każda klasa zawiera obiekt Convert, który zwraca wartość wyrównania (HorizontalAlignment lub VerticalAlignment).

    1. Dodaj nowy folder do projektu i nazwij go Konwertery.

    2. Dodaj dwie nowe klasy do folderu Konwertery (w tym przykładzie nazywamy je HorizontalAlignmentFromHandednessConverter.cs i VerticalAlignmentFromAppViewConverter.cs).

    3. Dodaj przestrzenie nazw using Windows.UI.Xaml i using Windows.UI.Xaml.Data do każdego pliku.

    4. Zmień każdą klasę na public i określ, że implementuje interfejs IValueConverter .

    5. Dodaj metody Convert i ConvertBack do każdego pliku, jak pokazano tutaj (pozostawimy niezaimplementowaną metodę ConvertBack).

      • HorizontalAlignmentFromHandednessConverter umieszcza pasek narzędzi pisma odręcznego po prawej stronie aplikacji dla użytkowników praworęcznych i po lewej stronie aplikacji dla użytkowników leworęcznych.
      using System;
      
      using Windows.UI.Xaml;
      using Windows.UI.Xaml.Data;
      
      namespace locationandorientation.Converters
      {
          public class HorizontalAlignmentFromHandednessConverter : IValueConverter
          {
              public object Convert(object value, Type targetType,
                  object parameter, string language)
              {
                  bool leftHanded = (bool)value;
                  HorizontalAlignment alignment = HorizontalAlignment.Right;
                  if (leftHanded)
                  {
                      alignment = HorizontalAlignment.Left;
                  }
                  return alignment;
              }
      
              public object ConvertBack(object value, Type targetType,
                  object parameter, string language)
              {
                  throw new NotImplementedException();
              }
          }
      }
      
      • VerticalAlignmentFromAppViewConverter umieszcza pasek narzędzi pióra w środku aplikacji dla orientacji pionowej i na górze aplikacji dla orientacji poziomej (ma to poprawić użyteczność, ale jest to jedynie arbitralny wybór w celach demonstracyjnych).
      using System;
      
      using Windows.UI.Xaml;
      using Windows.UI.Xaml.Data;
      
      namespace locationandorientation.Converters
      {
          public class VerticalAlignmentFromAppViewConverter : IValueConverter
          {
              public object Convert(object value, Type targetType,
                  object parameter, string language)
              {
                  bool portraitOrientation = (bool)value;
                  VerticalAlignment alignment = VerticalAlignment.Top;
                  if (portraitOrientation)
                  {
                      alignment = VerticalAlignment.Center;
                  }
                  return alignment;
              }
      
              public object ConvertBack(object value, Type targetType,
                  object parameter, string language)
              {
                  throw new NotImplementedException();
              }
          }
      }
      
  3. Teraz otwórz plik MainPage.xaml.cs.

    1. Dodaj using using locationandorientation.ViewModels do listy przestrzeni nazw, aby powiązać nasz ViewModel.
    2. Dodaj using Windows.UI.ViewManagement do listy przestrzeni nazw, aby umożliwić nasłuchiwanie zmian w orientacji urządzenia.
    3. Dodaj kod WindowSizeChangedEventHandler .
    4. Ustaw element DataContext dla widoku na pojedyncze wystąpienie klasy InkToolbarSnippetHostViewModel.
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    
    using locationandorientation.ViewModels;
    using Windows.UI.ViewManagement;
    
    namespace locationandorientation
    {
        public sealed partial class MainPage : Page
        {
            public MainPage()
            {
                this.InitializeComponent();
    
                Window.Current.SizeChanged += (sender, args) =>
                {
                    ApplicationView currentView = ApplicationView.GetForCurrentView();
    
                    if (currentView.Orientation == ApplicationViewOrientation.Landscape)
                    {
                        InkToolbarSnippetHostViewModel.Instance.PortraitLayout = false;
                    }
                    else if (currentView.Orientation == ApplicationViewOrientation.Portrait)
                    {
                        InkToolbarSnippetHostViewModel.Instance.PortraitLayout = true;
                    }
                };
    
                DataContext = InkToolbarSnippetHostViewModel.Instance;
            }
        }
    }
    
  4. Następnie otwórz plik MainPage.xaml.

    1. Dodaj xmlns:converters="using:locationandorientation.Converters" do elementu Page w celu powiązania z naszymi konwerterami.

      <Page
      x:Class="locationandorientation.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="using:locationandorientation"
      xmlns:converters="using:locationandorientation.Converters"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      mc:Ignorable="d">
      
    2. PageResources Dodaj element i określ odwołania do naszych konwerterów.

      <Page.Resources>
          <converters:HorizontalAlignmentFromHandednessConverter x:Key="HorizontalAlignmentConverter"/>
          <converters:VerticalAlignmentFromAppViewConverter x:Key="VerticalAlignmentConverter"/>
      </Page.Resources>
      
    3. Dodaj elementy InkCanvas i InkToolbar oraz powiąż właściwości VerticalAlignment i HorizontalAlignment paska narzędzi InkToolbar.

      <InkCanvas x:Name="inkCanvas" />
      <InkToolbar x:Name="inkToolbar" 
                  VerticalAlignment="{Binding PortraitLayout, Converter={StaticResource VerticalAlignmentConverter} }" 
                  HorizontalAlignment="{Binding LeftHandedLayout, Converter={StaticResource HorizontalAlignmentConverter} }" 
                  Orientation="Vertical" 
                  TargetInkCanvas="{x:Bind inkCanvas}" />
      
  5. Wróć do pliku InkToolbarSnippetHostViewModel.cs, aby dodać nasze PortraitLayout i LeftHandedLayout właściwości logiczne do klasy InkToolbarSnippetHostViewModel, wraz z obsługą odpowiedniego powiązania PortraitLayout w przypadku zmiany tej wartości właściwości.

    public bool LeftHandedLayout
    {
        get
        {
            bool leftHandedLayout = false;
            Windows.UI.ViewManagement.UISettings settings =
                new Windows.UI.ViewManagement.UISettings();
            leftHandedLayout = (settings.HandPreference ==
                Windows.UI.ViewManagement.HandPreference.LeftHanded);
            return leftHandedLayout;
        }
    }
    
    public bool portraitLayout = false;
    public bool PortraitLayout
    {
        get
        {
            Windows.UI.ViewManagement.ApplicationViewOrientation winOrientation = 
                Windows.UI.ViewManagement.ApplicationView.GetForCurrentView().Orientation;
            portraitLayout = 
                (winOrientation == 
                    Windows.UI.ViewManagement.ApplicationViewOrientation.Portrait);
            return portraitLayout;
        }
        set
        {
            if (value.Equals(portraitLayout)) return;
            portraitLayout = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("PortraitLayout"));
        }
    }
    
    #region INotifyPropertyChanged Members
    
    public event PropertyChangedEventHandler PropertyChanged;
    
    protected void OnPropertyChanged(string property)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
    }
    
    #endregion
    

Teraz powinna istnieć aplikacja pisma odręcznego, która dostosowuje się zarówno do dominujących preferencji użytkownika, jak i dynamicznie reaguje na orientację urządzenia użytkownika.

Określ wybrany przycisk

Przycisk ołówka wybrany podczas inicjowania
Pasek narzędzi Windows Ink z przyciskiem ołówka wybranym podczas uruchamiania

Domyślnie pierwszy (lub najbardziej lewy) przycisk jest wybierany po uruchomieniu aplikacji, a pasek narzędzi jest inicjowany. Na domyślnym pasku narzędzi Windows Ink jest to przycisk długopisu.

Ponieważ struktura definiuje kolejność wbudowanych przycisków, pierwszy przycisk może nie być piórem lub narzędziem, które chcesz aktywować domyślnie.

To zachowanie domyślne można zastąpić i określić wybrany przycisk na pasku narzędzi.

W tym przykładzie inicjujemy domyślny pasek narzędzi z wybranym przyciskiem ołówka i aktywowanym ołówkiem (zamiast długopisu).

  1. Użyj deklaracji XAML dla inkCanvas i InkToolbar z poprzedniego przykładu.
  2. W kodzie skonfiguruj procedurę obsługi dla załadowanego zdarzenia obiektu InkToolbar .
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// Here, we set up InkToolbar event listeners.
/// </summary>
public MainPage_CodeBehind()
{
    this.InitializeComponent();
    // Add handlers for InkToolbar events.
    inkToolbar.Loaded += inkToolbar_Loaded;
}
  1. W obsłudze zdarzenia Loaded:

    1. Uzyskaj odwołanie do wbudowanego elementu InkToolbarPencilButton.

    Przekazanie obiektu InkToolbarToolTool.Pencil w metodzie GetToolButton zwraca obiekt InkToolbarToolButton dla elementu InkToolbarPencilButton.

    1. Ustaw ActiveTool na obiekt zwrócony w poprzednim kroku.
/// <summary>
/// Handle the Loaded event of the InkToolbar.
/// By default, the active tool is set to the first tool on the toolbar.
/// Here, we set the active tool to the pencil button.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void inkToolbar_Loaded(object sender, RoutedEventArgs e)
{
    InkToolbarToolButton pencilButton = inkToolbar.GetToolButton(InkToolbarTool.Pencil);
    inkToolbar.ActiveTool = pencilButton;
}

Określanie wbudowanych przycisków

Określone przyciski dołączone do inicjowania
Określone przyciski dołączone do inicjowania

Jak wspomniano, pasek narzędzi Windows Ink zawiera kolekcję domyślnych, wbudowanych przycisków. Te przyciski są wyświetlane w następującej kolejności (od lewej do prawej):

W tym przykładzie zainicjujemy pasek narzędzi tylko za pomocą wbudowanych przycisków długopisu, ołówka i gumki.

Można to zrobić przy użyciu XAML lub kodu-behind.

XAML

Zmodyfikuj deklarację XAML dla inkCanvas i InkToolbar z pierwszego przykładu.

Uwaga / Notatka

Przyciski są dodawane do paska narzędzi w kolejności zdefiniowanej przez platformę, a nie do kolejności określonej tutaj.

<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" />
        <!-- Clear the default InkToolbar buttons by setting InitialControls to None. -->
        <!-- Set the active tool to the pencil button. -->
        <InkCanvas x:Name="inkCanvas" />
        <InkToolbar x:Name="inkToolbar"
                    VerticalAlignment="Top"
                    TargetInkCanvas="{x:Bind inkCanvas}"
                    InitialControls="None">
            <!--
             Add only the ballpoint pen, pencil, and eraser.
             Note that the buttons are added to the toolbar in the order
             defined by the framework, not the order we specify here.
            -->
            <InkToolbarEraserButton />
            <InkToolbarBallpointPenButton />
            <InkToolbarPencilButton/>
        </InkToolbar>
    </Grid>
</Grid>

Kod w tle

  1. Użyj deklaracji XAML dla inkCanvas i InkToolbar z pierwszego przykładu.
<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" />
        <InkToolbar x:Name="inkToolbar"
        VerticalAlignment="Top"
        TargetInkCanvas="{x:Bind inkCanvas}" />
    </Grid>
</Grid>
  1. W kodzie skonfiguruj procedurę obsługi dla zdarzenia ładowania obiektu InkToolbar .
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// Here, we set up InkToolbar event listeners.
/// </summary>
public MainPage_CodeBehind()
{
    this.InitializeComponent();
    // Add handlers for InkToolbar events.
    inkToolbar.Loading += inkToolbar_Loading;
}
  1. Ustaw InitialControls na "None".
  2. Utwórz odwołania do obiektów dla przycisków wymaganych przez aplikację. W tym miejscu dodajemy tylko InkToolbarBallpointPenButton, InkToolbarPencilButton i InkToolbarEraserButton .

Uwaga / Notatka

Przyciski są dodawane do paska narzędzi w kolejności zdefiniowanej przez platformę, a nie do kolejności określonej tutaj.

  1. Dodaj przyciski do paska InkToolbar.
/// <summary>
/// Handles the Loading event of the InkToolbar.
/// Here, we identify the buttons to include on the InkToolbar.
/// </summary>
/// <param name="sender">The InkToolbar</param>
/// <param name="args">The InkToolbar event data.
/// If there is no event data, this parameter is null</param>
private void inkToolbar_Loading(FrameworkElement sender, object args)
{
    // Clear all built-in buttons from the InkToolbar.
    inkToolbar.InitialControls = InkToolbarInitialControls.None;

    // Add only the ballpoint pen, pencil, and eraser.
    // Note that the buttons are added to the toolbar in the order
    // defined by the framework, not the order we specify here.
    InkToolbarBallpointPenButton ballpoint = new InkToolbarBallpointPenButton();
    InkToolbarPencilButton pencil = new InkToolbarPencilButton();
    InkToolbarEraserButton eraser = new InkToolbarEraserButton();
    inkToolbar.Children.Add(eraser);
    inkToolbar.Children.Add(ballpoint);
    inkToolbar.Children.Add(pencil);
}

Niestandardowe przyciski i funkcje pisma odręcznego

Możesz dostosować i rozszerzyć kolekcję przycisków (i skojarzonych funkcji pisma odręcznego), które są udostępniane za pomocą narzędzia InkToolbar.

Pasek narzędzi InkToolbar składa się z dwóch odrębnych grup przycisków:

  1. Grupa przycisków narzędzi zawierających wbudowane przyciski do rysowania, wymazywania i wyróżniania. W tym miejscu dodawane są spersonalizowane długopisy i narzędzia.

Uwaga Wybór funkcji jest wzajemnie wykluczający się.

  1. Grupa przycisków typu "przełącznik" zawierająca wbudowany przycisk linijki. W tym miejscu są dodawane niestandardowe przełączniki.

Uwaga Funkcje nie wykluczają się wzajemnie i mogą być używane jednocześnie z innymi aktywnymi narzędziami.

W zależności od aplikacji i wymaganej funkcji pisma odręcznego można dodać dowolny z następujących przycisków (powiązanych z niestandardowymi funkcjami pisma odręcznego) do paska narzędzi InkToolbar:

  • Pióro niestandardowe — pióro, dla którego paleta kolorów atramentu i właściwości końcówki pióra, takie jak kształt, obrót i rozmiar, są definiowane przez aplikację hosta.
  • Narzędzie niestandardowe — narzędzie inne niż pióro zdefiniowane przez aplikację macierzystą.
  • Przełącznik niestandardowy — ustawia stan funkcji zdefiniowanej przez aplikację na włączony lub wyłączony. Po włączeniu funkcja działa w połączeniu z aktywnym narzędziem.

Nuta Nie można zmienić kolejności wyświetlania wbudowanych przycisków. Domyślna kolejność wyświetlania to: długopis kulkowy, ołówek, zakreślacz, gumka i linijka. Niestandardowe pióra są dołączane do ostatniego domyślnego pióra, niestandardowe przyciski narzędzi są dodawane między ostatnim przyciskiem pióra a przyciskiem gumki, a niestandardowe przyciski przełączania są dodawane po przycisku linijki. (Przyciski niestandardowe są dodawane w takiej kolejności, jak zostały określone).

Pióro niestandardowe

Możesz utworzyć niestandardowe pióro (aktywowane za pomocą dedykowanego przycisku pióra), w którym zdefiniujesz paletę kolorów atramentu i właściwości końcówki pióra, takie jak kształt, obrót i rozmiar.

Niestandardowy przycisk pióra kaligraficznego
Przycisk pióra kaligraficznego niestandardowy

W tym przykładzie definiujemy niestandardowe pióro z szeroką końcówką, które umożliwia wykonywanie podstawowych kaligraficznych pociągnięć atramentem. Dostosowujemy również kolekcję pędzli w palecie wyświetlanej w menu rozwijanym przycisku.

Kod w tle

Najpierw definiujemy nasze niestandardowe pióro i określamy atrybuty rysunku w kodzie zaplecza. Odnosimy się do tego niestandardowego pędzla w XAML później.

  1. Kliknij prawym przyciskiem myszy projekt w Eksploratorze rozwiązań i wybierz polecenie Dodaj —> nowy element.
  2. W obszarze roboczym Visual C# —> Kod, dodaj nowy plik klasy i nazwij go CalligraphicPen.cs.
  3. W Calligraphic.cs zastąp wartość domyślną przy użyciu bloku następującym kodem:
using System.Numerics;
using Windows.UI;
using Windows.UI.Input.Inking;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
  1. Określ, że klasa CalligraphicPen pochodzi z Klasy InkToolbarCustomPen.
class CalligraphicPen : InkToolbarCustomPen
{
}
  1. Zastąpij metodę CreateInkDrawingAttributesCore , aby określić własny rozmiar pędzla i pociągnięcia.
class CalligraphicPen : InkToolbarCustomPen
{
    protected override InkDrawingAttributes
      CreateInkDrawingAttributesCore(Brush brush, double strokeWidth)
    {
    }
}
  1. Utwórz obiekt InkDrawingAttributes i ustaw kształt pióra, obrót końcówki, rozmiar pociągnięcia i kolor pisma odręcznego.
class CalligraphicPen : InkToolbarCustomPen
{
    protected override InkDrawingAttributes
      CreateInkDrawingAttributesCore(Brush brush, double strokeWidth)
    {
        InkDrawingAttributes inkDrawingAttributes =
          new InkDrawingAttributes();
        inkDrawingAttributes.PenTip = PenTipShape.Circle;
        inkDrawingAttributes.Size =
          new Windows.Foundation.Size(strokeWidth, strokeWidth * 20);
        SolidColorBrush solidColorBrush = brush as SolidColorBrush;
        if (solidColorBrush != null)
        {
            inkDrawingAttributes.Color = solidColorBrush.Color;
        }
        else
        {
            inkDrawingAttributes.Color = Colors.Black;
        }

        Matrix3x2 matrix = Matrix3x2.CreateRotation(45);
        inkDrawingAttributes.PenTipTransform = matrix;

        return inkDrawingAttributes;
    }
}

XAML

Następnie dodamy niezbędne odwołania do pióra niestandardowego w pliku MainPage.xaml.

  1. Deklarujemy słownik zasobów strony lokalnej, który tworzy odwołanie do niestandardowego pióra (CalligraphicPen) zdefiniowanego w CalligraphicPen.cs i kolekcji pędzli obsługiwanej przez pióro niestandardowe (CalligraphicPenPalette).
<Page.Resources>
    <!-- Add the custom CalligraphicPen to the page resources. -->
    <local:CalligraphicPen x:Key="CalligraphicPen" />
    <!-- Specify the colors for the palette of the custom pen. -->
    <BrushCollection x:Key="CalligraphicPenPalette">
        <SolidColorBrush Color="Blue" />
        <SolidColorBrush Color="Red" />
    </BrushCollection>
</Page.Resources>
  1. Następnie dodamy element InkToolbar z podrzędnym elementem InkToolbarCustomPenButton .

Przycisk niestandardowego długopisu obejmuje dwa odwołania do zasobów statycznych zadeklarowanych w zasobach strony: CalligraphicPen i CalligraphicPenPalette.

Określamy również zakres suwaka rozmiaru pociągnięcia (MinStrokeWidth, MaxStrokeWidth i SelectedStrokeWidth), wybranego pędzla (SelectedBrushIndex) i ikony niestandardowego przycisku pióra (SymbolIcon).

<Grid Grid.Row="1">
    <InkCanvas x:Name="inkCanvas" />
    <InkToolbar x:Name="inkToolbar"
                VerticalAlignment="Top"
                TargetInkCanvas="{x:Bind inkCanvas}">
        <InkToolbarCustomPenButton
            CustomPen="{StaticResource CalligraphicPen}"
            Palette="{StaticResource CalligraphicPenPalette}"
            MinStrokeWidth="1" MaxStrokeWidth="3" SelectedStrokeWidth="2"
            SelectedBrushIndex ="1">
            <SymbolIcon Symbol="Favorite" />
            <InkToolbarCustomPenButton.ConfigurationContent>
                <InkToolbarPenConfigurationControl />
            </InkToolbarCustomPenButton.ConfigurationContent>
        </InkToolbarCustomPenButton>
    </InkToolbar>
</Grid>

Przełącznik niestandardowy

Możesz utworzyć niestandardowy przełącznik (aktywowany za pomocą niestandardowego przycisku przełącznika), aby ustawić stan funkcji zdefiniowanej przez aplikację na włączony lub wyłączony. Po włączeniu funkcja działa w połączeniu z aktywnym narzędziem.

W tym przykładzie definiujemy niestandardowy przycisk przełączający, który umożliwia pisanie odręczne za pomocą dotyku (domyślnie pisanie odręczne przy użyciu dotyku nie jest włączone).

Uwaga / Notatka

Jeśli potrzebujesz obsługi pisania odręcznego za pomocą dotyku, zalecamy włączenie tej funkcji przy użyciu elementu CustomToggleButton, z ikoną i podpowiedzią ekranową określoną w tym przykładzie.

Zazwyczaj dane wejściowe dotykowe są używane do bezpośredniego manipulowania obiektem lub interfejsem użytkownika aplikacji. Aby zademonstrować różnice w zachowaniu po włączeniu pisma odręcznego dla dotyku, umieszczamy InkCanvas w kontenerze ScrollViewer i ustawiamy wymiary programu ScrollViewer na mniejsze niż InkCanvas.

Po uruchomieniu aplikacji obsługiwane jest tylko rysowanie piórem, a dotyk służy do przesuwania lub powiększania powierzchni. Po włączeniu funkcji pisania dotykowego, nie można przesuwać ani powiększać powierzchni do pisania za pomocą dotyku.

Uwaga / Notatka

Zobacz kontrolki pisma odręcznego zgodne z wytycznymi UX zarówno dla InkCanvas, jak i InkToolbar. Poniższe zalecenia są istotne dla tego przykładu:

  • InkToolbar oraz ogólnie funkcje pisania odręcznego najlepiej sprawdzają się w użyciu z aktywnym piórem. Jednak pisanie odręczne za pomocą myszy i dotyku może być obsługiwane, jeśli jest to wymagane przez aplikację.
  • Jeśli obsługiwane jest pisanie odręczne z wykorzystaniem wprowadzania dotykowego, zalecamy użycie ikony "ED5F" z czcionki "Segoe MLD2 Assets" dla przycisku przełącznika z etykietą narzędzia "Pisanie dotykowe".

XAML

  1. Najpierw deklarujemy element InkToolbarCustomToggleButton (toggleButton) za pomocą nasłuchiwacza zdarzeń Click, który określa procedurę obsługi zdarzeń (Toggle_Custom).
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

    <StackPanel Grid.Row="0" 
                x:Name="HeaderPanel" 
                Orientation="Horizontal">
        <TextBlock x:Name="Header" 
                   Text="Basic ink sample" 
                   Style="{ThemeResource HeaderTextBlockStyle}" 
                   Margin="10" />
    </StackPanel>

    <ScrollViewer Grid.Row="1" 
                  HorizontalScrollBarVisibility="Auto" 
                  VerticalScrollBarVisibility="Auto">
        
        <Grid HorizontalAlignment="Left" VerticalAlignment="Top">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            
            <InkToolbar Grid.Row="0" 
                        Margin="10"
                        x:Name="inkToolbar" 
                        VerticalAlignment="Top"
                        TargetInkCanvas="{x:Bind inkCanvas}">
                <InkToolbarCustomToggleButton 
                x:Name="toggleButton" 
                Click="CustomToggle_Click" 
                ToolTipService.ToolTip="Touch Writing">
                    <SymbolIcon Symbol="{x:Bind TouchWritingIcon}"/>
                </InkToolbarCustomToggleButton>
            </InkToolbar>
            
            <ScrollViewer Grid.Row="1" 
                          Height="500"
                          Width="500"
                          x:Name="scrollViewer" 
                          ZoomMode="Enabled" 
                          MinZoomFactor=".1" 
                          VerticalScrollMode="Enabled" 
                          VerticalScrollBarVisibility="Auto" 
                          HorizontalScrollMode="Enabled" 
                          HorizontalScrollBarVisibility="Auto">
                
                <Grid x:Name="outputGrid" 
                      Height="1000"
                      Width="1000"
                      Background="{ThemeResource SystemControlBackgroundChromeWhiteBrush}">
                    <InkCanvas x:Name="inkCanvas"/>
                </Grid>
                
            </ScrollViewer>
        </Grid>
    </ScrollViewer>
</Grid>

Kod w tle

  1. W poprzednim fragmencie kodu zadeklarowaliśmy odbiornik zdarzeń Click i procedurę obsługi (Toggle_Custom) na niestandardowym przycisku przełączania do dotykowego pisania odręcznego (toggleButton). Ta procedura obsługi po prostu przełącza obsługę CoreInputDeviceTypes.Touch poprzez właściwość InputDeviceTypes InkPresenter.

    Określiliśmy również ikonę dla przycisku, używając elementu SymbolIcon i rozszerzenia znaczników {x:Bind}, które wiąże ją z polem zdefiniowanym w pliku kodu (TouchWritingIcon).

    Poniższy fragment kodu zawiera zarówno procedurę obsługi zdarzenia Click, jak i definicję TouchWritingIcon.

namespace Ink_Basic_InkToolbar
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage_AddCustomToggle : Page
    {
        Symbol TouchWritingIcon = (Symbol)0xED5F;

        public MainPage_AddCustomToggle()
        {
            this.InitializeComponent();
        }

        // Handler for the custom toggle button that enables touch inking.
        private void CustomToggle_Click(object sender, RoutedEventArgs e)
        {
            if (toggleButton.IsChecked == true)
            {
                inkCanvas.InkPresenter.InputDeviceTypes |= CoreInputDeviceTypes.Touch;
            }
            else
            {
                inkCanvas.InkPresenter.InputDeviceTypes &= ~CoreInputDeviceTypes.Touch;
            }
        }
    }
}

Narzędzie niestandardowe

Możesz utworzyć niestandardowy przycisk narzędzia, aby wywołać zdefiniowane przez Twoją aplikację narzędzie inne niż pióro.

Domyślnie InkPresenter przetwarza wszystkie dane wejściowe jako pociągnięcie pisma odręcznego lub pociągnięcie wymazywania. Obejmuje to dane wejściowe zmodyfikowane przez dodatkową funkcję sprzętu, taką jak przycisk na piórze, prawy przycisk myszy lub podobny. Można jednak skonfigurować inkPresenter tak, aby dane wejściowe nie zostały przetworzone, które następnie można przekazać do aplikacji na potrzeby przetwarzania niestandardowego.

W tym przykładzie definiujemy niestandardowy przycisk narzędziowy, który po wybraniu powoduje przetworzenie kolejnych pociągnięć i renderowanie ich jako lasso zaznaczenia (kreskowana linia) zamiast pisma odręcznego. Wszystkie pociągnięcia tuszu w granicach obszaru zaznaczenia są ustawione na Zaznaczone.

Uwaga / Notatka

Zobacz kontrolki tuszu w wytycznych UX dotyczących InkCanvas i InkToolbar. Następujące zalecenie jest istotne dla tego przykładu:

  • W przypadku zaznaczenia linii zalecamy użycie ikony "EF20" z czcionki "Segoe MLD2 Assets" dla przycisku narzędzia z etykietką narzędzia "Narzędzie wyboru".

XAML

  1. Najpierw deklarujemy element InkToolbarCustomToolButton (customToolButton ) za pomocą odbiornika zdarzeń Click, który określa program obsługi zdarzeń (customToolButton_Click), w którym jest konfigurowany wybór pociągnięcia. (Dodaliśmy także zestaw przycisków do kopiowania, wycinania i wklejania zaznaczonego obszaru.)

  2. Dodamy również element canvas do rysowania naszego śladu zaznaczenia. Użycie oddzielnej warstwy, aby narysować obrys zaznaczenia, zapewnia, że InkCanvas i jego zawartość pozostają nietknięte.

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <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>
    <StackPanel x:Name="ToolPanel" Orientation="Horizontal" Grid.Row="1">
        <InkToolbar x:Name="inkToolbar" 
                    VerticalAlignment="Top" 
                    TargetInkCanvas="{x:Bind inkCanvas}">
            <InkToolbarCustomToolButton 
                x:Name="customToolButton" 
                Click="customToolButton_Click" 
                ToolTipService.ToolTip="Selection tool">
                <SymbolIcon Symbol="{x:Bind SelectIcon}"/>
            </InkToolbarCustomToolButton>
        </InkToolbar>
        <Button x:Name="cutButton" 
                Content="Cut" 
                Click="cutButton_Click"
                Width="100"
                Margin="5,0,0,0"/>
        <Button x:Name="copyButton" 
                Content="Copy"  
                Click="copyButton_Click"
                Width="100"
                Margin="5,0,0,0"/>
        <Button x:Name="pasteButton" 
                Content="Paste"  
                Click="pasteButton_Click"
                Width="100"
                Margin="5,0,0,0"/>
    </StackPanel>
    <Grid Grid.Row="2" x:Name="outputGrid" 
              Background="{ThemeResource SystemControlBackgroundChromeWhiteBrush}" 
              Height="Auto">
        <!-- Canvas for displaying selection UI. -->
        <Canvas x:Name="selectionCanvas"/>
        <!-- Canvas for displaying ink. -->
        <InkCanvas x:Name="inkCanvas" />
    </Grid>
</Grid>

Kod w tle

  1. Następnie obsługujemy zdarzenie Click dla elementu InkToolbarCustomToolButton w pliku kodu zaplecza MainPage.xaml.cs.

    Ta procedura obsługi konfiguruje narzędzie InkPresenter do przekazywania nieprzetworzonych danych wejściowych do aplikacji.

    Aby uzyskać bardziej szczegółowy opis działania tego kodu, zobacz sekcję Wprowadzanie przekazywane na potrzeby zaawansowanego przetwarzania w Interakcjach piórem i Windows Ink w aplikacjach systemu Windows.

    Określono również ikonę przycisku przy użyciu elementu SymbolIcon i rozszerzenia znaczników {x:Bind}, które wiąże je z polem zdefiniowanym w pliku za pomocą kodu (SelectIcon).

    Poniższy fragment kodu zawiera zarówno procedurę obsługi zdarzeń click, jak i definicję selectIcon.

namespace Ink_Basic_InkToolbar
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage_AddCustomTool : Page
    {
        // Icon for custom selection tool button.
        Symbol SelectIcon = (Symbol)0xEF20;

        // Stroke selection tool.
        private Polyline lasso;
        // Stroke selection area.
        private Rect boundingRect;

        public MainPage_AddCustomTool()
        {
            this.InitializeComponent();

            // Listen for new ink or erase strokes to clean up selection UI.
            inkCanvas.InkPresenter.StrokeInput.StrokeStarted +=
                StrokeInput_StrokeStarted;
            inkCanvas.InkPresenter.StrokesErased +=
                InkPresenter_StrokesErased;
        }

        private void customToolButton_Click(object sender, RoutedEventArgs e)
        {
            // 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;
        }

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

        private void cutButton_Click(object sender, RoutedEventArgs e)
        {
            inkCanvas.InkPresenter.StrokeContainer.CopySelectedToClipboard();
            inkCanvas.InkPresenter.StrokeContainer.DeleteSelected();
            ClearSelection();
        }

        private void copyButton_Click(object sender, RoutedEventArgs e)
        {
            inkCanvas.InkPresenter.StrokeContainer.CopySelectedToClipboard();
        }

        private void pasteButton_Click(object sender, RoutedEventArgs e)
        {
            if (inkCanvas.InkPresenter.StrokeContainer.CanPasteFromClipboard())
            {
                inkCanvas.InkPresenter.StrokeContainer.PasteFromClipboard(
                    new Point(0, 0));
            }
            else
            {
                // Cannot paste from clipboard.
            }
        }

        // Clean up selection UI.
        private void ClearSelection()
        {
            var strokes = inkCanvas.InkPresenter.StrokeContainer.GetStrokes();
            foreach (var stroke in strokes)
            {
                stroke.Selected = false;
            }
            ClearBoundingRect();
        }

        private void ClearBoundingRect()
        {
            if (selectionCanvas.Children.Any())
            {
                selectionCanvas.Children.Clear();
                boundingRect = Rect.Empty;
            }
        }

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

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

Niestandardowe renderowanie atramentu

Domyślnie dane wejściowe pisma odręcznego są przetwarzane na wątku w tle o małych opóźnieniach i renderowane jako "mokre", gdy są rysowane. Po ukończeniu pociągnięcia (gdy pióro lub palec zostanie uniesiony lub przycisk myszy zwolniony), pociągnięcie jest przetwarzane na wątku interfejsu użytkownika i renderowane jako „suche” na warstwie InkCanvas (umieszczonej powyżej zawartości aplikacji, zastępując mokry atrament).

Platforma pisma odręcznego umożliwia zastąpienie tego zachowania i całkowite dostosowanie środowiska pisma odręcznego przez niestandardowe suszenie danych wejściowych pisma odręcznego.

Aby uzyskać więcej informacji na temat suszenia niestandardowego, zobacz Interakcje piórem i Atrament systemu Windows w aplikacjach systemu Windows.

Uwaga / Notatka

Niestandardowe suszenie i narzędzie InkToolbar
Jeśli aplikacja zastępuje domyślne zachowanie renderowania pisma odręcznego w narzędziu InkPresenter niestandardową implementacją wysychania, renderowane pociągnięcia pisma odręcznego nie są już dostępne dla InkToolbar, a wbudowane polecenia wymazywania InkToolbar nie działają zgodnie z oczekiwaniami. Aby zapewnić funkcjonalność wymazywania, należy obsługiwać wszystkie zdarzenia wskaźnika, wykonywać testy trafień na każdym pociągnięciu i zastępować wbudowane polecenie "Wymaż wszystkie atramenty".

Przykłady tematów

Inne przykłady