Menambahkan InkToolbar ke aplikasi Windows

Ada dua kontrol berbeda yang memfasilitasi penintaan di aplikasi Windows: InkCanvas dan InkToolbar.

Kontrol InkCanvas menyediakan fungsionalitas Windows Ink dasar. Gunakan untuk merender input pena sebagai goresan tinta (menggunakan pengaturan default untuk warna dan ketebalan) atau hapus goresan.

Untuk detail implementasi InkCanvas, lihat Interaksi pena dan stylus di aplikasi Windows.

Sebagai overlay yang sepenuhnya transparan, InkCanvas tidak menyediakan UI bawaan untuk mengatur properti goresan tinta. Jika Anda ingin mengubah pengalaman penintaan default, biarkan pengguna mengatur properti goresan tinta, dan mendukung fitur penintaan kustom lainnya, Anda memiliki dua opsi:

  • Di code-behind, gunakan objek InkPresenter yang mendasar yang terikat ke InkCanvas.

    API InkPresenter mendukung penyesuaian yang luas dari pengalaman penintaan. Untuk detail selengkapnya, lihat Interaksi pena dan stylus di aplikasi Windows.

  • Ikat InkToolbar ke InkCanvas. Secara default, InkToolbar menyediakan koleksi tombol yang dapat disesuaikan dan dapat diperluas untuk mengaktifkan fitur terkait tinta seperti ukuran goresan, warna tinta, dan ujung pena.

    Kami membahas InkToolbar dalam topik ini.

API Penting: Kelas InkCanvas, kelas InkToolbar, kelas InkPresenter, Windows.UI.Input.Inking

Baku InkToolbar

Secara default, InkToolbar menyertakan tombol untuk menggambar, menghapus, menyoroti, dan menampilkan stensil (penggaris atau protraktor). Tergantung pada fitur, pengaturan dan perintah lainnya, seperti warna tinta, ketebalan goresan, menghapus semua tinta, disediakan dalam flyout.

InkToolbar
Bilah alat Tinta Windows Default

Untuk menambahkan InkToolbar default ke aplikasi penintaan, cukup letakkan di halaman yang sama dengan InkCanvas Anda dan kaitkan dua kontrol.

  1. Di MainPage.xaml, deklarasikan objek kontainer (untuk contoh ini, kami menggunakan kontrol Grid) untuk permukaan penintaan.
  2. Deklarasikan objek InkCanvas sebagai anak dari kontainer. (Ukuran InkCanvas diwarisi dari kontainer.)
  3. Deklarasikan InkToolbar dan gunakan atribut TargetInkCanvas untuk mengikatnya ke InkCanvas.

Catatan

Pastikan InkToolbar dideklarasikan setelah InkCanvas. Jika tidak, overlay InkCanvas merender InkToolbar tidak dapat diakses.

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

Kustomisasi dasar

Di bagian ini, kami membahas beberapa skenario kustomisasi toolbar Windows Ink dasar.

Tentukan lokasi dan orientasi

Saat menambahkan toolbar tinta ke aplikasi, Anda dapat menerima lokasi default dan orientaion toolbar atau mengaturnya sebagaimana diperlukan oleh aplikasi atau pengguna Anda.

XAML

Tentukan lokasi dan orientasi toolbar secara eksplisit melalui properti VerticalAlignment, HorizontalAlignment, dan Orientasinya.

Default Eksplisit
Default ink toolbar location and orientation Explicit ink toolbar location and orientation
Lokasi dan orientasi default bilah alat Windows Ink Lokasi dan orientasi eksplisit toolbar Windows Ink

Berikut adalah kode untuk secara eksplisit mengatur lokasi dan orientasi toolbar tinta di XAML.

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

Menginisialisasi berdasarkan preferensi pengguna atau status perangkat

Dalam beberapa kasus, Anda mungkin ingin mengatur lokasi dan orientasi toolbar tinta berdasarkan preferensi pengguna atau status perangkat. Contoh berikut menunjukkan cara mengatur lokasi dan orientasi toolbar tinta berdasarkan preferensi penulisan sebelah kiri atau kanan yang ditentukan melalui Pengaturan Pena Perangkat > & Pena Tinta >> Windows Pilih tangan mana yang Anda tulis. >

Dominant hand setting
Pengaturan tangan dominan

Anda dapat mengkueri pengaturan ini melalui properti HandPreference Windows.UI.ViewManagement dan mengatur HorizontalAlignment berdasarkan nilai yang dikembalikan. Dalam contoh ini, kami menemukan toolbar di sisi kiri aplikasi untuk orang bertangan kiri dan di sisi kanan untuk orang dengan tangan kanan.

Unduh sampel ini dari lokasi toolbar Tinta dan sampel orientasi (dasar)

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

Menyesuaikan secara dinamis dengan status pengguna atau perangkat

Anda juga dapat menggunakan pengikatan untuk menjaga pembaruan UI berdasarkan perubahan pada preferensi pengguna, pengaturan perangkat, atau status perangkat. Dalam contoh berikut, kami memperluas contoh sebelumnya dan menunjukkan cara memosisikan toolbar tinta secara dinamis berdasarkan orientasi perangkat menggunakan pengikatan, objek ViewMOdel, dan antarmuka INotifyPropertyChanged .

Unduh sampel ini dari lokasi toolbar Tinta dan sampel orientasi (dinamis)

  1. Pertama, mari kita tambahkan ViewModel kita.

    1. Tambahkan folder baru ke proyek Anda dan sebut saja ViewModels.

    2. Tambahkan kelas baru ke folder ViewModels (untuk contoh ini, kami menyebutnya InkToolbarSnippetHostViewModel.cs).

      Catatan

      Kami menggunakan pola Singleton karena kami hanya membutuhkan satu objek jenis ini untuk masa pakai aplikasi

    3. Tambahkan using System.ComponentModel namespace ke file.

    4. Tambahkan variabel anggota statis yang disebut instans, dan properti baca saja statis bernama Instans. Jadikan konstruktor privat untuk memastikan kelas ini hanya dapat diakses melalui properti Instans.

      Catatan

      Kelas ini mewarisi dari antarmuka INotifyPropertyChanged , yang digunakan untuk memberi tahu klien, biasanya mengikat klien, bahwa nilai properti telah berubah. Kami akan menggunakan ini untuk menangani perubahan pada orientasi perangkat (kami akan memperluas kode ini dan menjelaskan lebih lanjut di langkah selanjutnya).

      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. Tambahkan dua properti bool ke kelas InkToolbarSnippetHostViewModel: LeftHandedLayout (fungsionalitas yang sama dengan contoh khusus XAML sebelumnya) dan PortraitLayout (orientasi perangkat).

      Catatan

      Properti PortraitLayout dapat diatur dan menyertakan penentuan untuk peristiwa 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. Sekarang, mari kita tambahkan beberapa kelas konverter ke proyek kita. Setiap kelas berisi objek Konversi yang mengembalikan nilai perataan (HorizontalAlignment atau VerticalAlignment).

    1. Tambahkan folder baru ke proyek Anda dan sebut saja Pengonversi.

    2. Tambahkan dua kelas baru ke folder Converters (misalnya, kami menyebutnya HorizontalAlignmentFromHandednessConverter.cs dan VerticalAlignmentFromAppViewConverter.cs).

    3. Tambahkan using Windows.UI.Xaml dan using Windows.UI.Xaml.Data namespace ke setiap file.

    4. Ubah setiap kelas menjadi public dan tentukan bahwa ia mengimplementasikan antarmuka IValueConverter .

    5. Tambahkan metode Konversi dan Konversi Balik ke setiap file, seperti yang ditunjukkan di sini (kami membiarkan metode ConvertBack tidak di-unimplementasi).

      • HorizontalAlignmentFromHandednessConverter memposisikan toolbar tinta ke sisi kanan aplikasi untuk pengguna dengan tangan kanan dan di sisi kiri aplikasi untuk pengguna sebelah kiri.
      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 memposisikan toolbar tinta ke tengah aplikasi untuk orientasi potret dan ke bagian atas aplikasi untuk orientasi lanskap (sementara dimaksudkan untuk meningkatkan kegunaan, ini hanyalah pilihan sewenang-wenang untuk tujuan demonstrasi).
      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. Sekarang, buka file MainPage.xaml.cs.

    1. Tambahkan using using locationandorientation.ViewModels ke daftar namespace layanan untuk mengaitkan ViewModel kami.
    2. Tambahkan using Windows.UI.ViewManagement ke daftar namespace layanan untuk mengaktifkan mendengarkan perubahan pada orientasi perangkat.
    3. Tambahkan kode WindowSizeChangedEventHandler.
    4. Atur DataContext untuk tampilan ke instans singleton kelas 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. Selanjutnya, buka file MainPage.xaml.

    1. Tambahkan xmlns:converters="using:locationandorientation.Converters" ke Page elemen untuk pengikatan ke konverter kami.

      <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 Tambahkan elemen dan tentukan referensi ke konverter kami.

      <Page.Resources>
          <converters:HorizontalAlignmentFromHandednessConverter x:Key="HorizontalAlignmentConverter"/>
          <converters:VerticalAlignmentFromAppViewConverter x:Key="VerticalAlignmentConverter"/>
      </Page.Resources>
      
    3. Tambahkan elemen InkCanvas dan InkToolbar dan ikat properti VerticalAlignment dan HorizontalAlignment dari 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. Kembali ke file InkToolbarSnippetHostViewModel.cs untuk menambahkan properti kami PortraitLayout dan LeftHandedLayout bool ke InkToolbarSnippetHostViewModel kelas , bersama dengan dukungan untuk pengikatan PortraitLayout ulang ketika nilai properti tersebut berubah.

    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
    

Anda sekarang harus memiliki aplikasi penintaan yang beradaptasi dengan preferensi tangan dominan pengguna dan secara dinamis merespons orientasi perangkat pengguna.

Tentukan tombol terpilih

Pencil button selected at initialization
Bilah alat Windows Ink dengan tombol pensil dipilih saat inisialisasi

Secara default, tombol pertama (atau paling kiri) dipilih saat aplikasi Anda diluncurkan dan toolbar diinisialisasi. Di toolbar Windows Ink default, ini adalah tombol pena ballpoint.

Karena kerangka kerja menentukan urutan tombol bawaan, tombol pertama mungkin bukan pena atau alat yang ingin Anda aktifkan secara default.

Anda dapat mengambil alih perilaku default ini dan menentukan tombol yang dipilih pada bilah alat.

Untuk contoh ini, kami menginisialisasi toolbar default dengan tombol pensil dipilih dan pensil diaktifkan (alih-alih pena ballpoint).

  1. Gunakan deklarasi XAML untuk InkCanvas dan InkToolbar dari contoh sebelumnya.
  2. Di code-behind, siapkan handler untuk peristiwa Yang dimuat dari objek 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. Di handler untuk peristiwa Dimuat :

    1. Dapatkan referensi ke InkToolbarPencilButton bawaan.

    Meneruskan objek InkToolbarTool.Pencil dalam metode GetToolButton mengembalikan objek InkToolbarToolButton untuk InkToolbarPencilButton.

    1. Atur ActiveTool ke objek yang dikembalikan di langkah sebelumnya.
/// <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;
}

Tentukan tombol bawaan

Specific buttons included at initialization
Tombol tertentu disertakan pada inisialisasi

Seperti disebutkan, toolbar Windows Ink menyertakan kumpulan tombol bawaan default. Tombol ini ditampilkan dalam urutan berikut (dari kiri ke kanan):

Untuk contoh ini, kami menginisialisasi toolbar hanya dengan tombol pen, pensil, dan penghapus ballpoint bawaan.

Anda dapat melakukan ini menggunakan XAML atau code-behind.

XAML

Ubah deklarasi XAML untuk InkCanvas dan InkToolbar dari contoh pertama.

Catatan

Tombol ditambahkan ke toolbar dalam urutan yang ditentukan oleh kerangka kerja, bukan urutan yang ditentukan di sini.

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

Kode di belakang

  1. Gunakan deklarasi XAML untuk InkCanvas dan InkToolbar dari contoh pertama.
<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. Di code-behind, siapkan handler untuk peristiwa Pemuatan objek 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. Atur InitialControls ke "None".
  2. Buat referensi objek untuk tombol yang diperlukan oleh aplikasi Anda. Di sini, kami menambahkan InkToolbarBallpointPenButton, InkToolbarPencilButton, dan InkToolbarEraserButton saja.

Catatan

Tombol ditambahkan ke toolbar dalam urutan yang ditentukan oleh kerangka kerja, bukan urutan yang ditentukan di sini.

  1. Tambahkan tombol ke 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);
}

Tombol kustom dan fitur penintaan

Anda dapat menyesuaikan dan memperluas pengumpulan tombol (dan fitur penintaan terkait) yang disediakan melalui InkToolbar.

InkToolbar terdiri dari dua grup jenis tombol yang berbeda:

  1. Sekelompok tombol "alat" yang berisi tombol gambar, penghapusan, dan penyorotan bawaan. Pena dan alat kustom ditambahkan di sini.

Pilihan Fitur Catatan saling eksklusif.

  1. Sekelompok tombol "beralih" yang berisi tombol penggaris bawaan. Tombol kustom ditambahkan di sini.

Fitur Catatan tidak saling eksklusif dan dapat digunakan bersamaan dengan alat aktif lainnya.

Bergantung pada aplikasi dan fungsionalitas penintaan yang diperlukan, Anda dapat menambahkan salah satu tombol berikut (terikat ke fitur tinta kustom Anda) ke InkToolbar:

  • Pena kustom – pena tempat palet warna tinta dan properti ujung pena, seperti bentuk, rotasi, dan ukuran, ditentukan oleh aplikasi host.
  • Alat kustom – alat non-pena, yang ditentukan oleh aplikasi host.
  • Tombol kustom – Mengatur status fitur yang ditentukan aplikasi ke aktif atau nonaktif. Saat diaktifkan, fitur ini berfungsi bersama dengan alat aktif.

Catatan Anda tidak dapat mengubah urutan tampilan tombol bawaan. Urutan tampilan default adalah: Pena Ballpoint, pensil, penyorot, penghapus, dan penggaris. Pena kustom ditambahkan ke pena default terakhir, tombol alat kustom ditambahkan antara tombol pena terakhir dan tombol penghapus dan tombol pengalih kustom ditambahkan setelah tombol penggaris. (Tombol kustom ditambahkan dalam urutan yang ditentukan.)

Pena kustom

Anda dapat membuat pena kustom (diaktifkan melalui tombol pena kustom) tempat Anda menentukan palet warna tinta dan properti ujung pena, seperti bentuk, rotasi, dan ukuran.

Custom calligraphic pen button
Tombol pena kaligrafi kustom

Untuk contoh ini, kami mendefinisikan pena kustom dengan tip luas yang memungkinkan goresan tinta kaligrafi dasar. Kami juga menyesuaikan koleksi kuas di palet yang ditampilkan pada flyout tombol.

Kode di belakang

Pertama, kami mendefinisikan pena kustom kami dan menentukan atribut gambar di code-behind. Kami mereferensikan pena kustom ini dari XAML nanti.

  1. Klik kanan proyek di Penjelajah Solusi dan pilih Tambahkan -> Item baru.
  2. Di bawah Visual C# -> Kode, tambahkan file Kelas baru dan sebut saja CalligraphicPen.cs.
  3. Di Calligraphic.cs, ganti default menggunakan blok dengan yang berikut ini:
using System.Numerics;
using Windows.UI;
using Windows.UI.Input.Inking;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
  1. Tentukan bahwa kelas CalligraphicPen berasal dari InkToolbarCustomPen.
class CalligraphicPen : InkToolbarCustomPen
{
}
  1. Ganti CreateInkDrawingAttributesCore untuk menentukan ukuran kuas dan goresan Anda sendiri.
class CalligraphicPen : InkToolbarCustomPen
{
    protected override InkDrawingAttributes
      CreateInkDrawingAttributesCore(Brush brush, double strokeWidth)
    {
    }
}
  1. Buat objek InkDrawingAttributes dan atur bentuk ujung pena, rotasi tip, ukuran goresan, dan warna tinta.
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

Selanjutnya, kami menambahkan referensi yang diperlukan ke pena kustom di MainPage.xaml.

  1. Kami mendeklarasikan kamus sumber daya halaman lokal yang membuat referensi ke pena kustom (CalligraphicPen) yang ditentukan dalam CalligraphicPen.cs, dan koleksi kuas yang didukung oleh pena kustom (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. Kami kemudian menambahkan InkToolbar dengan elemen InkToolbarCustomPenButton anak.

Tombol pena kustom menyertakan dua referensi sumber daya statis yang dideklarasikan dalam sumber daya halaman: CalligraphicPen dan CalligraphicPenPalette.

Kami juga menentukan rentang untuk penggeser ukuran goresan (MinStrokeWidth, MaxStrokeWidth, dan SelectedStrokeWidth), kuas yang dipilih (SelectedBrushIndex), dan ikon untuk tombol pena kustom (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>

Tombol kustom

Anda dapat membuat tombol kustom (diaktifkan melalui tombol alih kustom) untuk mengatur status fitur yang ditentukan aplikasi ke aktif atau nonaktif. Saat diaktifkan, fitur ini berfungsi bersama dengan alat aktif.

Dalam contoh ini, kami menentukan tombol pengalih kustom yang memungkinkan penintaan dengan input sentuhan (secara default, penintaan sentuhan tidak diaktifkan).

Catatan

Jika Anda perlu mendukung penintaan dengan sentuhan, kami sarankan Anda mengaktifkannya menggunakan CustomToggleButton, dengan ikon dan tipsalat yang ditentukan dalam contoh ini.

Biasanya, input sentuh digunakan untuk manipulasi langsung objek atau UI aplikasi. Untuk menunjukkan perbedaan perilaku saat tinta sentuh diaktifkan, kami menempatkan InkCanvas dalam kontainer ScrollViewer dan mengatur dimensi ScrollViewer agar lebih kecil dari InkCanvas.

Saat aplikasi dimulai, hanya penintaan pena yang didukung dan sentuhan digunakan untuk menggeser atau memperbesar permukaan penintaan. Saat tinta sentuh diaktifkan, permukaan penintaan tidak dapat dipanen atau diperbesar melalui input sentuhan.

Catatan

Lihat Kontrol penintaan untuk panduan UX InkCanvas dan InkToolbar. Rekomendasi berikut relevan dengan contoh ini:

  • InkToolbar, dan penintaan secara umum, paling baik dialami melalui pena aktif. Namun, penintaan dengan mouse dan sentuhan dapat didukung jika diperlukan oleh aplikasi Anda.
  • Jika mendukung penintaan dengan input sentuh, sebaiknya gunakan ikon "ED5F" dari font "Segoe MLD2 Assets" untuk tombol alih, dengan tipsalat "Penulisan sentuhan".

XAML

  1. Pertama, kami mendeklarasikan elemen InkToolbarCustomToggleButton (toggleButton) dengan pendengar peristiwa Klik yang menentukan penanganan aktivitas (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>

Kode di belakang

  1. Dalam cuplikan sebelumnya, kami mendeklarasikan Pendengar peristiwa Klik dan handler (Toggle_Custom) pada tombol pengalih kustom untuk tinta sentuh (toggleButton). Handler ini hanya mengalihkan dukungan untuk CoreInputDeviceTypes.Touch melalui properti InputDeviceTypes dari InkPresenter.

    Kami juga menentukan ikon untuk tombol menggunakan elemen SymbolIcon dan ekstensi markup {x:Bind} yang mengikatnya ke bidang yang ditentukan dalam file code-behind (TouchWritingIcon).

    Cuplikan berikut mencakup penanganan aktivitas Klik dan definisi 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;
            }
        }
    }
}

Alat kustom

Anda dapat membuat tombol alat kustom untuk memanggil alat non-pena yang ditentukan oleh aplikasi Anda.

Secara default, InkPresenter memproses semua input sebagai goresan tinta atau menghapus stroke. Ini termasuk input yang dimodifikasi oleh keterlibatan perangkat keras sekunder seperti tombol barel pena, tombol mouse kanan, atau sejenisnya. Namun, InkPresenter dapat dikonfigurasi untuk membiarkan input tertentu tidak diproses, yang kemudian dapat diteruskan ke aplikasi Anda untuk pemrosesan kustom.

Dalam contoh ini, kami menentukan tombol alat kustom yang, ketika dipilih, menyebabkan goresan berikutnya diproses dan dirender sebagai lasso pilihan (garis putus-putus) alih-alih tinta. Semua goresan tinta dalam batas area pilihan diatur ke Dipilih.

Catatan

Lihat Kontrol penintaan untuk panduan UX InkCanvas dan InkToolbar. Rekomendasi berikut relevan dengan contoh ini:

  • Jika memberikan pilihan stroke, sebaiknya gunakan ikon "EF20" dari font "Segoe MLD2 Assets" untuk tombol alat, dengan tipsalat "Alat pemilihan".

XAML

  1. Pertama, kami mendeklarasikan elemen InkToolbarCustomToolButton (customToolButton) dengan pendengar peristiwa Klik yang menentukan penanganan aktivitas (customToolButton_Click) tempat pemilihan goresan dikonfigurasi. (Kami juga telah menambahkan sekumpulan tombol untuk menyalin, memotong, dan menempelkan pilihan goresan.)

  2. Kami juga menambahkan elemen Canvas untuk menggambar goresan pilihan kami. Menggunakan lapisan terpisah untuk menggambar goresan pemilihan memastikan InkCanvas dan kontennya tetap tidak tersentuh.

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

Kode di belakang

  1. Kami kemudian menangani peristiwa Klik untuk file InkToolbarCustomToolButton di file kode MainPage.xaml.cs- di belakang.

    Handler ini mengonfigurasi InkPresenter untuk meneruskan input yang tidak diolah ke aplikasi.

    Untuk langkah yang lebih rinci tentang kode ini: Lihat bagian Input pass-through untuk pemrosesan lanjutan interaksi Pena dan Windows Ink di aplikasi Windows.

    Kami juga menentukan ikon untuk tombol menggunakan elemen SymbolIcon dan ekstensi markup {x:Bind} yang mengikatnya ke bidang yang ditentukan dalam file code-behind (SelectIcon).

    Cuplikan berikut mencakup penanganan aktivitas Klik dan definisi 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 modifed 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);
            }
        }
    }
}

Penyajian tinta kustom

Secara default, input tinta diproses pada utas latar belakang latensi rendah dan dirender "basah" saat digambar. Ketika goresan selesai (pena atau jari diangkat, atau tombol mouse dilepaskan), goresan diproses pada utas UI dan dirender "kering" ke lapisan InkCanvas (di atas konten aplikasi dan mengganti tinta basah).

Platform tinta memungkinkan Anda untuk mengambil alih perilaku ini dan sepenuhnya menyesuaikan pengalaman penintaan dengan mengeringkan input tinta secara kustom.

Untuk informasi selengkapnya tentang pengeringan kustom, lihat Interaksi pena dan Windows Ink di aplikasi Windows.

Catatan

Pengeringan kustom dan InkToolbar
Jika aplikasi Anda mengambil alih perilaku penyajian tinta default InkPresenter dengan implementasi pengeringan kustom, goresan tinta yang dirender tidak lagi tersedia untuk InkToolbar dan perintah penghapusan bawaan InkToolbar tidak berfungsi seperti yang diharapkan. Untuk menyediakan fungsionalitas penghapusan, Anda harus menangani semua peristiwa penunjuk, melakukan pengujian hit pada setiap goresan, dan mengambil alih perintah "Hapus semua tinta" bawaan.

Sampel topik

Sampel lainnya