Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Esistono due controlli diversi che facilitano l'inserimento digitale nelle app Windows: InkCanvas e InkToolbar.
Il controllo InkCanvas fornisce funzionalità di base di Windows Ink. Utilizzare per visualizzare l'input da penna come tratto d'inchiostro (utilizzando le impostazioni predefinite per colore e spessore) o come tratto di cancellazione.
Per informazioni dettagliate sull'implementazione di InkCanvas, vedi Interazioni tramite penna e stilo nelle app di Windows.
Come sovrimpressione completamente trasparente, InkCanvas non fornisce alcuna interfaccia utente incorporata per l'impostazione delle proprietà del tratto d'inchiostro. Se si vuole modificare l'esperienza di input penna predefinita, consentire agli utenti di impostare le proprietà del tratto input penna e supportare altre funzionalità di input penna personalizzate, sono disponibili due opzioni:
Nel code-behind usare l'oggetto InkPresenter sottostante associato a InkCanvas.
Le API InkPresenter supportano una vasta personalizzazione dell'esperienza di inchiostrazione. Per altri dettagli, vedi Interazioni con penna e stilo nelle app di Windows.
Associare un InkToolbar all'InkCanvas. Il controllo InkToolbar, per impostazione predefinita, offre una raccolta personalizzabile ed estendibile di pulsanti per l'attivazione di funzionalità relative all'inchiostro, come la larghezza del tratto, il colore dell'inchiostro e la punta della penna.
In questo argomento viene illustrato InkToolbar.
API importanti: classe InkCanvas, classe InkToolbar, classe InkPresenter, Windows.UI.Input.Inking
InkToolbar predefinito
Per impostazione predefinita, InkToolbar include pulsanti per disegno, cancellazione, evidenziazione e visualizzazione di uno stencil (righello o protractore). A seconda della funzionalità, altre impostazioni e comandi, ad esempio il colore dell'inchiostro, lo spessore del tratto, l'opzione Cancella tutto l'inchiostro, vengono forniti in un riquadro a comparsa.
Barra degli strumenti predefinita di Windows Ink
Per aggiungere un controllo InkToolbar predefinito a un'app per inchiostrazione, posizionarlo nella stessa pagina di InkCanvas e associare i due controlli.
- In MainPage.xaml, dichiarare un oggetto contenitore (per questo esempio viene usato un controllo Grid) per la superficie d'inchiostro.
- Dichiarare un oggetto InkCanvas come figlio del contenitore. Le dimensioni di InkCanvas sono ereditate dal contenitore.
- Dichiarare un InkToolbar e usare l'attributo TargetInkCanvas per legarlo a InkCanvas.
Annotazioni
Verificare che l'InkToolbar sia dichiarata dopo l'InkCanvas. In caso contrario, la sovrapposizione InkCanvas rende InkToolbar inaccessibile.
<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>
Personalizzazione di base
In questa sezione vengono illustrati alcuni scenari di personalizzazione della barra degli strumenti di Windows Ink di base.
Specificare la posizione e l'orientamento
Quando aggiungi una barra degli strumenti input penna all'app, puoi accettare la posizione e l'orientamento predefiniti della barra degli strumenti o impostarli come richiesto dall'app o dall'utente.
XAML
Specificare in modo esplicito la posizione e l'orientamento della barra degli strumenti tramite le proprietà VerticalAlignment, HorizontalAlignment e Orientation .
| Impostazione predefinita | Explicit |
|---|---|
|
|
| Posizione e orientamento predefiniti della barra degli strumenti di Windows Ink | Posizione e orientamento espliciti della barra degli strumenti di Windows Ink |
Ecco il codice per impostare esplicitamente la posizione e l'orientamento della barra degli strumenti ink in XAML.
<InkToolbar x:Name="inkToolbar"
VerticalAlignment="Center"
HorizontalAlignment="Right"
Orientation="Vertical"
TargetInkCanvas="{x:Bind inkCanvas}" />
Inizializzare in base alle preferenze utente o allo stato del dispositivo
In alcuni casi, è possibile impostare la posizione e l'orientamento della barra degli strumenti input penna in base alle preferenze utente o allo stato del dispositivo. Nell'esempio seguente viene illustrato come impostare la posizione e l'orientamento della barra degli strumenti dell'input penna in base alle preferenze di scrittura a sinistra o a destra specificate tramite Impostazioni > Dispositivi > Penna e Windows Ink > Scegli quale mano usare per scrivere.
Impostazione della mano dominante
È possibile eseguire una query su questa impostazione tramite la proprietà HandPreference di Windows.UI.ViewManagement e impostare HorizontalAlignment in base al valore restituito. In questo esempio si individua la barra degli strumenti sul lato sinistro dell'app per una persona sinistra e sul lato destro per una persona destra.
Scarica questo esempio dalla barra degli strumenti Ink - esempio di posizione e orientamento (base)
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;
}
Modificare dinamicamente lo stato dell'utente o del dispositivo
È anche possibile usare l'associazione per controllare gli aggiornamenti dell'interfaccia utente in base alle modifiche apportate alle preferenze utente, alle impostazioni del dispositivo o agli stati del dispositivo. Nell'esempio seguente, si espande l'esempio precedente e si mostra come posizionare dinamicamente la barra degli strumenti dell'inchiostro in base all'orientamento del dispositivo usando il binding, un oggetto ViewModel e l'interfaccia INotifyPropertyChanged.
Scarica questo esempio dal campione di posizione e orientamento della Toolbar dell'inchiostro (dinamico)
Prima di tutto, aggiungiamo il viewModel.
Aggiungere una nuova cartella al progetto e chiamarla ViewModels.
Aggiungere una nuova classe alla cartella ViewModels (per questo esempio è stata chiamata InkToolbarSnippetHostViewModel.cs).
Annotazioni
È stato usato il modello Singleton perché è necessario un solo oggetto di questo tipo per la durata dell'applicazione
Aggiungere
using System.ComponentModelnamespace al file.Aggiungere una variabile membro statica denominata istanza e una proprietà di sola lettura statica denominata Instance. Rendere privato il costruttore per assicurarsi che questa classe sia accessibile solo tramite la proprietà Instance.
Annotazioni
Questa classe eredita dall'interfaccia INotifyPropertyChanged , che viene usata per notificare ai client, in genere i client di associazione, che un valore della proprietà è stato modificato. Verrà usato per gestire le modifiche apportate all'orientamento del dispositivo (questo codice verrà espanso e illustrato più avanti in un passaggio successivo).
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() { } }Aggiungere due proprietà bool alla classe InkToolbarSnippetHostViewModel: LeftHandedLayout (stessa funzionalità dell'esempio XAML precedente) e PortraitLayout (orientamento del dispositivo).
Annotazioni
La proprietà PortraitLayout è impostabile e include la definizione per l'evento 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")); } }
A questo punto, aggiungere un paio di classi di convertitore al progetto. Ogni classe contiene un oggetto Convert che restituisce un valore di allineamento ( HorizontalAlignment o VerticalAlignment).
Aggiungere una nuova cartella al progetto e chiamarla Converters.
Aggiungere due nuove classi alla cartella Converters (per questo esempio le chiamiamo HorizontalAlignmentFromHandednessConverter.cs e VerticalAlignmentFromAppViewConverter.cs).
Aggiungere i namespace
using Windows.UI.Xamleusing Windows.UI.Xaml.Dataa ogni file.Modificare ogni classe in
publice specificare che implementa l'interfaccia IValueConverter .Aggiungere i metodi Convert e ConvertBack a ogni file, come illustrato di seguito (si lascia il metodo ConvertBack non implementato).
- HorizontalAlignmentFromHandednessConverter posiziona la barra degli strumenti input penna sul lato destro dell'app per gli utenti di destra e sul lato sinistro dell'app per gli utenti sinistro.
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 posiziona la barra degli strumenti per l'inchiostrazione al centro dell'app per l'orientamento verticale e alla sommità dell'app per l'orientamento orizzontale (anche se intende migliorare l'usabilità, questa è solo una scelta arbitraria a scopo dimostrativo).
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(); } } }
Aprire ora il file di MainPage.xaml.cs.
- Aggiungere
using using locationandorientation.ViewModelsall'elenco degli spazi dei nomi per associare il nostro ViewModel. - Aggiungere
using Windows.UI.ViewManagementall'elenco dei namespace per abilitare l'ascolto delle modifiche all'orientamento del dispositivo. - Aggiungere il codice WindowSizeChangedEventHandler .
- Impostare DataContext per la visualizzazione sull'istanza singleton della classe 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; } } }- Aggiungere
Aprire quindi il file MainPage.xaml.
Aggiungere
xmlns:converters="using:locationandorientation.Converters"all'elementoPageper il collegamento ai nostri convertitori.<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">Aggiungere un elemento
PageResourcese specificare i riferimenti ai convertitori.<Page.Resources> <converters:HorizontalAlignmentFromHandednessConverter x:Key="HorizontalAlignmentConverter"/> <converters:VerticalAlignmentFromAppViewConverter x:Key="VerticalAlignmentConverter"/> </Page.Resources>Aggiungere gli elementi InkCanvas e InkToolbar e associare le proprietà VerticalAlignment e HorizontalAlignment di 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}" />
Tornare al file di InkToolbarSnippetHostViewModel.cs per aggiungere le nostre proprietà
PortraitLayoute boolLeftHandedLayoutalla classeInkToolbarSnippetHostViewModel, insieme al supporto per il riassociamentoPortraitLayoutquando il valore di quella proprietà cambia.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
Ora dovresti avere un'app di inchiostrazione che si adatta sia alla preferenza della mano dominante dell'utente sia risponde dinamicamente all'orientamento del dispositivo dell'utente.
Specificare il pulsante selezionato
Barra degli strumenti di Windows Ink con il pulsante a forma di matita selezionato all'inizializzazione
Per impostazione predefinita, il primo pulsante (o all'estrema sinistra) viene selezionato all'avvio dell'app e la barra degli strumenti viene inizializzata. Nella barra degli strumenti predefinita di Windows Ink, questo è il pulsante penna a sfera.
Poiché il framework definisce l'ordine dei pulsanti predefiniti, il primo pulsante potrebbe non essere la penna o lo strumento da attivare per impostazione predefinita.
È possibile eseguire l'override di questo comportamento predefinito e specificare il pulsante selezionato sulla barra degli strumenti.
Per questo esempio, inizializziamo la barra degli strumenti predefinita con il pulsante della matita selezionato e la matita attivata (anziché la penna del punto a sfera).
- Usare la dichiarazione XAML per InkCanvas e InkToolbar dell'esempio precedente.
- Nel file di code-behind, configurare un gestore per l'evento Loaded dell'oggetto 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;
}
Nel gestore per l'evento Loaded :
- Ottenere un riferimento all'oggetto InkToolbarPencilButton predefinito.
Il passaggio di un oggetto InkToolbarTool.Pencil nel metodo GetToolButton restituisce un oggetto InkToolbarToolButton per InkToolbarPencilButton.
- Impostare ActiveTool sull'oggetto restituito nel passaggio precedente.
/// <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;
}
Specificare i pulsanti predefiniti
Pulsanti specifici inclusi all'inizializzazione
Come accennato, la barra degli strumenti di Windows Ink include una raccolta di pulsanti predefiniti. Questi pulsanti vengono visualizzati nell'ordine seguente (da sinistra a destra):
- InkToolbarBallpointPenButton
- InkToolbarPencilButton
- InkToolbarHighlighterButton
- InkToolbarEraserButton
- InkToolbarRulerButton
Per questo esempio, inizializziamo la barra degli strumenti con solo i pulsanti predefiniti per il punto a sfera, la matita e la gomma.
Puoi farlo usando XAML o code-behind.
XAML
Modificare la dichiarazione XAML per InkCanvas e InkToolbar dal primo esempio.
- Aggiungere un attributo InitialControls e impostarne il valore su "None". In questo modo viene cancellata la raccolta predefinita di pulsanti predefiniti.
- Aggiungere i pulsanti InkToolbar specifici richiesti dall'app. Qui aggiungiamo solo InkToolbarBallpointPenButton, InkToolbarPencilButton e InkToolbarEraserButton.
Annotazioni
I pulsanti vengono aggiunti alla barra degli strumenti nell'ordine definito dal framework, non l'ordine specificato qui.
<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>
Code-behind
- Usare la dichiarazione XAML per InkCanvas e InkToolbar del primo esempio.
<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>
- Nel codice sottostante configurare un gestore per l'evento Loading dell'oggetto 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;
}
- Impostare InitialControls su "None".
- Creare riferimenti agli oggetti per i pulsanti richiesti dall'app. Qui aggiungiamo InkToolbarBallpointPenButton, InkToolbarPencilButton e InkToolbarEraserButton soltanto.
Annotazioni
I pulsanti vengono aggiunti alla barra degli strumenti nell'ordine definito dal framework, non l'ordine specificato qui.
- Aggiungere i pulsanti a 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);
}
Pulsanti personalizzati e funzionalità di inchiostrazione
È possibile personalizzare ed estendere la raccolta di pulsanti (e le funzionalità di inchiostro associate) offerte tramite InkToolbar.
InkToolbar è costituito da due gruppi distinti di tipi di pulsanti:
- Gruppo di pulsanti "strumento" contenenti i pulsanti predefiniti di disegno, cancellazione ed evidenziazione. Qui vengono aggiunti penne e strumenti personalizzati.
Nota La selezione di funzionalità si esclude a vicenda.
- Gruppo di pulsanti di attivazione/disattivazione contenenti il pulsante del righello predefinito. Qui vengono aggiunti interruttori personalizzati.
Nota Le funzionalità non si escludono a vicenda e possono essere usate simultaneamente con altri strumenti attivi.
A seconda dell'applicazione e delle funzionalità di input penna necessarie, è possibile aggiungere uno dei pulsanti seguenti (associati alle funzionalità di input penna personalizzate) a InkToolbar:
- Penna personalizzata: una penna per la quale la tavolozza dei colori input penna e le proprietà della punta della penna, ad esempio forma, rotazione e dimensioni, sono definite dall'app host.
- Strumento personalizzato: uno strumento non penna, definito dall'app host.
- Interruttore personalizzato: imposta lo stato di una funzionalità definita dall'app su attivato o disattivato. Quando è attivata, la funzionalità funziona insieme allo strumento attivo.
Nota Non è possibile modificare l'ordine di visualizzazione dei pulsanti predefiniti. L'ordine di visualizzazione predefinito è: penna, matita, evidenziatore, gomma e righello. Le penne personalizzate vengono aggiunte all'ultima penna predefinita, i pulsanti degli strumenti personalizzati vengono aggiunti tra l'ultimo pulsante della penna e il pulsante della gomma e i pulsanti di attivazione/disattivazione personalizzati vengono aggiunti dopo il pulsante del righello. I pulsanti personalizzati vengono aggiunti nell'ordine in cui sono specificati.
Penna personalizzata
È possibile creare una penna personalizzata (attivata tramite un pulsante di penna personalizzato) in cui si definiscono la tavolozza dei colori input penna e le proprietà della punta della penna, ad esempio forma, rotazione e dimensioni.
Pulsante personalizzato per penna calligrafica
Per questo esempio, definiamo una penna personalizzata con punta ampia che consente tratti calligrafici di base. Noi personalizziamo anche la raccolta di pennelli nella tavolozza visualizzata su riquadro a comparsa del pulsante.
Code-behind
Prima di tutto, definiamo la penna personalizzata e specifichiamo gli attributi del disegno nel code-behind. Fare riferimento a questa penna personalizzata da XAML in un secondo momento.
- Fare clic con il pulsante destro del mouse sul progetto in Esplora soluzioni e selezionare Aggiungi -> Nuovo elemento.
- In Visual C# -> Codice aggiungere un nuovo file di classe e chiamarlo CalligraphicPen.cs.
- In Calligraphic.cs sostituire il blocco using predefinito con quanto segue:
using System.Numerics;
using Windows.UI;
using Windows.UI.Input.Inking;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
- Specificare che la classe CalligraphicPen è derivata da InkToolbarCustomPen.
class CalligraphicPen : InkToolbarCustomPen
{
}
- Sovrascrivere CreateInkDrawingAttributesCore per specificare le dimensioni del pennello e del tratto.
class CalligraphicPen : InkToolbarCustomPen
{
protected override InkDrawingAttributes
CreateInkDrawingAttributesCore(Brush brush, double strokeWidth)
{
}
}
- Creare un oggetto InkDrawingAttributes e impostare la forma della punta della penna, la rotazione della punta, la dimensione del tratto e il colore dell'input penna.
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
Aggiungere quindi i riferimenti necessari alla penna personalizzata in MainPage.xaml.
- Dichiariamo un dizionario risorse pagina locale che crea un riferimento alla penna personalizzata (
CalligraphicPen) definita in CalligraphicPen.cs e una raccolta di pennelli supportata dalla penna personalizzata (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>
- Aggiungiamo quindi una InkToolbar con un elemento figlio InkToolbarCustomPenButton.
Il pulsante della penna personalizzata include i due riferimenti alle risorse statiche dichiarate nelle risorse della pagina: CalligraphicPen e CalligraphicPenPalette.
Specifichiamo anche il range per lo slider delle dimensioni del tratto (MinStrokeWidth, MaxStrokeWidth e SelectedStrokeWidth), il pennello selezionato (SelectedBrushIndex) e l'icona per il pulsante penna personalizzata (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>
Interruttore personalizzato
È possibile creare un interruttore personalizzato (attivato tramite un pulsante di attivazione/disattivazione personalizzato) per impostare lo stato di una funzionalità definita dall'app su attivato o disattivato. Quando è attivata, la funzionalità funziona insieme allo strumento attivo.
In questo esempio viene definito un pulsante di attivazione/disattivazione personalizzato che consente l'input penna con input tocco (per impostazione predefinita, l'input penna tramite tocco non è abilitato).
Annotazioni
Se devi supportare l'inserimento con penna utilizzando il tocco, raccomandiamo di abilitarlo usando CustomToggleButton, con l'icona e la descrizione comando specificati in questo esempio.
In genere, l'input tocco viene usato per la manipolazione diretta di un oggetto o dell'interfaccia utente dell'app. Per illustrare le differenze di comportamento quando l'input tattile è abilitato, si inserisce InkCanvas all'interno di un contenitore ScrollViewer e si impostano le dimensioni di ScrollViewer in modo che siano minori di InkCanvas.
All'avvio dell'app è supportata solo la scrittura a penna e il tocco viene utilizzato per eseguire la panoramica o lo zoom della superficie di scrittura. Quando l'inchiostrazione tramite tocco è abilitata, la superficie di inchiostrazione non può essere scorsa o ingrandita con il tocco.
Annotazioni
Vedere i controlli input penna per le linee guida sull'UX di InkCanvas e InkToolbar. I consigli seguenti sono rilevanti per questo esempio:
- InkToolbar, e l'uso dell'inchiostro in generale, è meglio sperimentato tramite una penna attiva. Tuttavia, l'input penna con mouse e tocco può essere supportato se richiesto dall'app.
- Se si supporta la scrittura con penna tramite input tocco, è consigliabile usare l'icona "ED5F" del tipo di carattere "Segoe MLD2 Assets" per il pulsante di attivazione/disattivazione, con un suggerimento "Scrittura tocco".
XAML
- In primo luogo, dichiariamo un elemento InkToolbarCustomToggleButton (toggleButton) con un listener di eventi Click che specifica il gestore eventi (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>
Code-behind
Nel frammento di codice precedente è stato dichiarato un listener di eventi Click e un gestore (Toggle_Custom) sul pulsante di attivazione/disattivazione personalizzato per l'input da touchscreen e inking (toggleButton). Questo gestore attiva semplicemente il supporto per CoreInputDeviceTypes.Touch tramite la proprietà InputDeviceTypes di InkPresenter.
È stata specificata anche un'icona per il pulsante usando l'elemento SymbolIcon e l'estensione di markup {x:Bind} che lo associa a un campo definito nel file code-behind (TouchWritingIcon).
Il frammento di codice seguente include sia il gestore eventi Click che la definizione di 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;
}
}
}
}
Strumento personalizzato
È possibile creare un pulsante dello strumento personalizzato per richiamare uno strumento non penna definito dall'applicazione.
Per impostazione predefinita, un InkPresenter elabora tutti gli input come un tratto di inchiostro o un tratto di cancellazione. Ciò include l'input modificato da un dispositivo hardware secondario, come il pulsante della penna, il pulsante destro del mouse o altri simili. Tuttavia, InkPresenter può essere configurato per lasciare un input specifico non elaborato, che può quindi essere passato all'app per l'elaborazione personalizzata.
In questo esempio, definiamo un pulsante dello strumento personalizzato che, se selezionato, fa sì che i tratti successivi vengano elaborati e visualizzati come un lasso di selezione (linea tratteggiata) anziché come inchiostro digitale. Tutti i tratti di inchiostro all'interno dei limiti dell'area di selezione sono impostati su Selezionato.
Annotazioni
Consultare i controlli per la scrittura digitale nelle linee guida UX di InkCanvas e InkToolbar. Il consiglio seguente è rilevante per questo esempio:
- Se si specifica la selezione del tratto, è consigliabile usare l'icona "EF20" dal font "Segoe MLD2 Assets" per il pulsante dello strumento, con un tooltip "Strumento di selezione".
XAML
In primo luogo, dichiariamo un elemento InkToolbarCustomToolButton (customToolButton) con un listener di eventi Click che specifica il gestore eventi (customToolButton_Click) in cui è configurata la selezione del tratto. È stato anche aggiunto un set di pulsanti per copiare, tagliare e incollare la selezione del tratto.
Aggiungiamo anche un elemento Canvas per disegnare il tratto di selezione. L'uso di un livello separato per disegnare il tratto di selezione garantisce che InkCanvas e il relativo contenuto rimangano invariati.
<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>
Code-behind
Gestiamo quindi l'evento Click per InkToolbarCustomToolButton nel file code-behind MainPage.xaml.cs.
Questo gestore configura InkPresenter per passare l'input non elaborato all'app.
Per un'analisi più dettagliata di questo codice: consulta la sezione Input pass-through per l'elaborazione avanzata di Interazioni con penna e Windows Ink nelle app di Windows.
È stata specificata anche un'icona per il pulsante usando l'elemento SymbolIcon e l'estensione di markup {x:Bind} che lo associa a un campo definito nel file code-behind (SelectIcon).
Il frammento di codice seguente include sia il gestore eventi Click che la definizione di 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);
}
}
}
}
Rendering dell'inchiostro personalizzato
Per impostazione predefinita, l'input penna viene elaborato in un thread in background a bassa latenza e reso "bagnato" man mano che viene disegnato. Quando il tratto viene completato (penna o dito sollevato o pulsante del mouse rilasciato), il tratto viene elaborato sul thread dell'interfaccia utente e viene eseguito il rendering "asciutto" sul livello InkCanvas (sopra il contenuto dell'applicazione e sostituendo l'inchiostro bagnato).
La piattaforma di input penna consente di eseguire l'override di questo comportamento e di personalizzare completamente l'esperienza di input penna, utilizzando l'asciugatura personalizzata dell'input di penna.
Per altre info sull'essiccazione personalizzata, vedi Interazioni con penna e Windows Ink nelle app di Windows.
Annotazioni
Essiccazione personalizzata e InkToolbar
Se l'app modifica il comportamento di rendering inchiostro predefinito di InkPresenter con un'implementazione personalizzata di asciugatura, i tratti di inchiostro resi non sono più disponibili per InkToolbar e i comandi di cancellazione integrati di InkToolbar non funzionano come previsto. Per fornire funzionalità di cancellazione, è necessario gestire tutti gli eventi del puntatore, eseguire la verifica delle collisioni su ogni tratto ed eseguire l'override del comando integrato "Cancella tutto l'inchiostro".
Articoli correlati
Esempi di argomenti
- Esempio di posizione e orientamento della barra degli strumenti penna (base)
- Esempio di orientamento e posizione della barra degli strumenti input penna (dinamico)