Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Er zijn twee verschillende besturingselementen waarmee handschrift in Windows-apps mogelijk is: InkCanvas en InkToolbar.
Het besturingselement InkCanvas biedt eenvoudige Windows Ink-functionaliteit. Gebruik deze functie om peninvoer weer te geven als een pennenstreek (met behulp van standaardinstellingen voor kleur en dikte) of als een uitgewiste streek.
Zie Pen- en stylusinteracties in Windows-apps voor inkCanvas-implementatiedetails.
Als een volledig transparante overlay biedt De InkCanvas geen ingebouwde gebruikersinterface voor het instellen van pennenstrekeneigenschappen. Als u de standaard inktervaring wilt wijzigen, kunt u gebruikers de eigenschappen van pennenstreken laten instellen en andere aangepaste inktfuncties ondersteunen. U hebt twee opties:
Gebruik in code-behind het onderliggende InkPresenter-object dat is gebonden aan inkCanvas.
De InkPresenter-API's ondersteunen uitgebreide aanpassing van de inktervaring. Zie Pen- en stylusinteracties in Windows-apps voor meer informatie.
Bind een InkToolbar aan de InkCanvas. Standaard biedt de InkToolbar een aanpasbare en uitbreidbare verzameling knoppen voor het activeren van inktgerelateerde functies, zoals pennenstreekgrootte, inktkleur en pentip.
In dit onderwerp bespreken we de InkToolbar.
Belangrijke API's: Klasse InkCanvas, Klasse InkToolbar, InkPresenter-klasse, Windows.UI.Input.Inking
Standaard InkToolbar
Standaard bevat de InkToolbar knoppen voor tekenen, wissen, markeren en weergeven van een stencil (liniaal of aftrekken). Afhankelijk van de functie worden andere instellingen en opdrachten, zoals inktkleur, lijndikte, en alle inkt wissen, weergegeven in een flyout.
Standaardwerkbalk van Windows Ink
Als u een standaard InkToolbar wilt toevoegen aan een tekenapp, plaatst u deze op dezelfde pagina als uw InkCanvas en koppelt u de twee besturingselementen.
- Declareer in MainPage.xaml een containerobject (in dit voorbeeld gebruiken we een rasterbesturing) voor het inktoppervlak.
- Declareer een InkCanvas-object als een kind-element van de container. (De grootte van InkCanvas wordt overgenomen van de container.)
- Declareer een InkToolbar en gebruik het kenmerk TargetInkCanvas om deze aan de InkCanvas te binden.
Opmerking
Zorg ervoor dat de InkToolbar is gedeclareerd na de InkCanvas. Als dat niet het geval is, maakt de InkCanvas-overlay de InkToolbar ontoegankelijk.
<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>
Basisaanpassing
In deze sectie behandelen we enkele eenvoudige aanpassingsscenario's voor windows Ink-werkbalken.
Locatie en oriëntatie opgeven
Wanneer u een inktwerkbalk aan uw app toevoegt, kunt u de standaardlocatie en afdrukstand van de werkbalk accepteren of deze instellen zoals vereist voor uw app of gebruiker.
XAML
Geef expliciet de locatie en stand van de werkbalk op via de eigenschappen VerticalAlignment, HorizontalAlignment en Orientation .
| Verstek | Expliciet |
|---|---|
|
|
| Standaardlocatie en afdrukstand van de Windows Ink-werkbalk | Expliciete locatie en oriëntatie van de Windows Ink-werkbalk |
Hier volgt de code voor het expliciet instellen van de locatie en stand van de inktwerkbalk in XAML.
<InkToolbar x:Name="inkToolbar"
VerticalAlignment="Center"
HorizontalAlignment="Right"
Orientation="Vertical"
TargetInkCanvas="{x:Bind inkCanvas}" />
Initialiseren op basis van gebruikersvoorkeuren of apparaatstatus
In sommige gevallen wilt u mogelijk de locatie en stand van de inktwerkbalk instellen op basis van de gebruikersvoorkeur of apparaatstatus. In het volgende voorbeeld ziet u hoe u de locatie en oriëntatie van de inktwerkbalk instelt op basis van de voorkeuren voor links- of rechtshandig schrijven die zijn opgegeven via
Instellingen voor de dominante hand
U kunt deze instelling opvragen via de eigenschap HandPreference van Windows.UI.ViewManagement en de HorizontalAlignment instellen op basis van de geretourneerde waarde. In dit voorbeeld zoeken we de werkbalk aan de linkerkant van de app voor een linkshandige persoon en aan de rechterkant voor een rechtshandige persoon.
Download dit voorbeeld van de locatie en oriëntatie van de Ink werkbalk (basis)
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;
}
Dynamisch aanpassen aan de gebruikers- of apparaatstatus
U kunt ook binding gebruiken om te controleren op ui-updates op basis van wijzigingen in gebruikersvoorkeuren, apparaatinstellingen of apparaatstatussen. In het volgende voorbeeld gaan we verder met het vorige voorbeeld en laten we zien hoe u de inktwerkbalk dynamisch kunt positioneren op basis van apparaatstand met behulp van binding, een ViewMOdel-object en de interface INotifyPropertyChanged .
Eerst gaan we ons ViewModel toevoegen.
Voeg een nieuwe map toe aan uw project en noem deze ViewModels.
Voeg een nieuwe klasse toe aan de map ViewModels (in dit voorbeeld noemen we deze InkToolbarSnippetHostViewModel.cs).
Opmerking
We hebben het Singleton-patroon gebruikt omdat we slechts één object van dit type nodig hebben voor de levensduur van de toepassing
Voeg
using System.ComponentModelde naamruimte toe aan het bestand.Voeg een statische lidvariabele met de naam exemplaar toe en een statische alleen-lezen-eigenschap met de naam Exemplaar. Maak de constructor privé om ervoor te zorgen dat deze klasse alleen toegankelijk is via de eigenschap Instance.
Opmerking
Deze klasse neemt over van de INotifyPropertyChanged-interface , die wordt gebruikt om clients te waarschuwen, meestal bindingsclients, dat een eigenschapswaarde is gewijzigd. We gaan dit gebruiken om wijzigingen in de oriëntatie van het apparaat af te handelen (we zullen deze code later uitbreiden en verder uitleggen in een volgende stap).
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() { } }Voeg twee bool-eigenschappen toe aan de klasse InkToolbarSnippetHostViewModel: LeftHandedLayout (dezelfde functionaliteit als het vorige XAML-voorbeeld) en PortraitLayout (afdrukstand van het apparaat).
Opmerking
De eigenschap PortraitLayout kan worden ingesteld en bevat de definitie voor de PropertyChanged gebeurtenis.
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")); } }
Laten we nu een aantal conversieklassen toevoegen aan ons project. Elke klasse bevat een Converteren-object dat een uitlijningswaarde retourneert ( HorizontalAlignment of VerticalAlignment).
Voeg een nieuwe map toe aan uw project en noem deze Converters.
Voeg twee nieuwe klassen toe aan de map Conversieprogramma's (in dit voorbeeld noemen we ze HorizontalAlignmentFromHandednessConverter.cs en VerticalAlignmentFromAppViewConverter.cs).
Add
using Windows.UI.Xamlenusing Windows.UI.Xaml.Datanaamruimten toe aan elk bestand.Wijzig elke klasse in
publicen geef op dat deze de IValueConverter-interface implementeert.Voeg de methoden Convert en ConvertBack toe aan elk bestand, zoals hier wordt weergegeven (we laten de Methode ConvertBack ongemplementeerd).
- HorizontalAlignmentFromHandednessConverter plaatst de inktwerkbalk aan de rechterkant van de app voor rechtshandige gebruikers en aan de linkerkant van de app voor linkshandige gebruikers.
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 plaatst de inktwerkbalk in het midden van de app voor portretmodus en bovenaan in de app voor landschapsmodus (hoewel dit bedoeld is om de bruikbaarheid te verbeteren, is dit slechts een arbitraire keuze voor demonstratiedoeleinden).
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(); } } }
Open nu het bestand MainPage.xaml.cs.
- Voeg toe
using using locationandorientation.ViewModelsaan de lijst met naamruimten om ons ViewModel te koppelen. - Voeg
using Windows.UI.ViewManagementtoe aan de naamruimtelijst om te luisteren naar wijzigingen in de apparaatstand. - Voeg de code WindowSizeChangedEventHandler toe.
- Stel de DataContext voor de weergave in op het singleton-exemplaar van de klasse 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; } } }- Voeg toe
Open vervolgens het bestand MainPage.xaml.
Voeg
xmlns:converters="using:locationandorientation.Converters"toe aan hetPageelement voor binding met onze conversieprogramma's.<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">Voeg een
PageResourceselement toe en geef verwijzingen op naar onze conversieprogramma's.<Page.Resources> <converters:HorizontalAlignmentFromHandednessConverter x:Key="HorizontalAlignmentConverter"/> <converters:VerticalAlignmentFromAppViewConverter x:Key="VerticalAlignmentConverter"/> </Page.Resources>Voeg de elementen InkCanvas en InkToolbar toe en bind de eigenschappen VerticalAlignment en HorizontalAlignment van de 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}" />
Ga terug naar het InkToolbarSnippetHostViewModel.cs-bestand om onze
PortraitLayouteigenschappen enLeftHandedLayoutbool-eigenschappen toe te voegen aan deInkToolbarSnippetHostViewModelklasse, samen met ondersteuning voor opnieuw koppelenPortraitLayoutwanneer die eigenschapswaarde wordt gewijzigd.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
U moet nu een teken-app hebben die zowel aan de dominante handvoorkeur van de gebruiker als aan de oriëntatie van het apparaat dynamisch aanpast.
De geselecteerde knop opgeven
Windows Ink-werkbalk met potloodknop geselecteerd bij initialisatie
Standaard wordt de eerste (of meest linkse) knop geselecteerd wanneer uw app wordt gestart en de werkbalk wordt geïnitialiseerd. In de standaardwerkbalk van Windows Ink is dit de balpenknop.
Omdat het framework de volgorde van de ingebouwde knoppen definieert, is de eerste knop mogelijk niet de pen of het hulpprogramma dat u standaard wilt activeren.
U kunt dit standaardgedrag overschrijven en de geselecteerde knop op de werkbalk opgeven.
In dit voorbeeld initialiseren we de standaardwerkbalk met de potloodknop geselecteerd en het potlood geactiveerd (in plaats van de balpen).
- Gebruik de XAML-declaratie voor de InkCanvas- en InkToolbar uit het vorige voorbeeld.
- Stel in code-behind een handler in voor de Loaded-gebeurtenis van het InkToolbar-object.
/// <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;
}
In de handler voor de geladen gebeurtenis:
- Haal een verwijzing op naar de ingebouwde InkToolbarPencilButton.
Het doorgeven van een InkToolbarTool.Pencil-object in de methode GetToolButton retourneert een InkToolbarToolButton-object voor het InkToolbarPencilButton.
- Stel ActiveTool in op het object dat in de vorige stap is geretourneerd.
/// <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;
}
De ingebouwde knoppen opgeven
Specifieke knoppen bij initialisatie
Zoals vermeld, bevat de werkbalk Windows Ink een verzameling standaardknoppen. Deze knoppen worden weergegeven in de volgende volgorde (van links naar rechts):
- InkToolbarBallpointPenButton
- InkToolbarPencilButton
- InkToolbarHighlighterButton
- InkToolbarEraserButton
- InkToolbarRulerButton
In dit voorbeeld initialiseren we de toolbar met alleen de ingebouwde balpenknop, potloodknoppen en gumknoppen.
U kunt dit doen met behulp van XAML of code-behind.
XAML
Wijzig de XAML-declaratie voor de InkCanvas- en InkToolbar uit het eerste voorbeeld.
- Voeg een InitialControls-kenmerk toe en stel de waarde ervan in op Geen. Hierdoor wordt de standaardverzameling van ingebouwde knoppen gewist.
- Voeg de specifieke InkToolbar-knoppen toe die vereist zijn voor uw app. Hier voegen we alleen InkToolbarBallpointPenButton, InkToolbarPencilButton en InkToolbarEraserButton toe.
Opmerking
Knoppen worden toegevoegd aan de werkbalk in de volgorde die is gedefinieerd door het framework, niet de volgorde die hier is opgegeven.
<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
- Gebruik de XAML-declaratie voor de InkCanvas- en InkToolbar uit het eerste voorbeeld.
<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>
- Stel in code-behind een handler in voor de gebeurtenis Laden van het Object 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;
}
- Stel InitialControls in op "Geen".
- Maak objectverwijzingen voor de knoppen die vereist zijn voor uw app. Hier voegen we alleen InkToolbarBallpointPenButton, InkToolbarPencilButton en InkToolbarEraserButton toe.
Opmerking
Knoppen worden toegevoegd aan de werkbalk in de volgorde die is gedefinieerd door het framework, niet de volgorde die hier is opgegeven.
- Voeg de knoppen toe aan de 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);
}
Aangepaste knoppen en inktenfuncties
U kunt de verzameling knoppen (en bijbehorende inktfuncties) aanpassen en uitbreiden die via de InkToolbar worden geleverd.
De InkToolbar bestaat uit twee afzonderlijke groepen knoptypen:
- Een groep 'tool'-knoppen met de ingebouwde knoppen voor tekenen, wissen en markeren. Hier worden aangepaste pennen en gereedschap toegevoegd.
Notitie Functieselectie is wederzijds exclusief.
- Een groep 'wisselknoppen' met de ingebouwde liniaalknop. Hier worden aangepaste wisselknoppen toegevoegd.
Notitie Functies sluiten elkaar niet uit en kunnen gelijktijdig worden gebruikt met andere actieve hulpprogramma's.
Afhankelijk van uw toepassing en de benodigde inktfunctionaliteit, kunt u een van de volgende knoppen (afhankelijk van uw aangepaste inktfuncties) toevoegen aan de InkToolbar:
- Aangepaste pen: een pen waarvoor het kleurenpalet en de eigenschappen van de pentip, zoals vorm, draaiing en grootte, worden gedefinieerd door de host-app.
- Aangepast hulpprogramma: een niet-penhulpprogramma dat is gedefinieerd door de host-app.
- Aangepaste wisselknop: hiermee stelt u de status van een door de app gedefinieerde functie in of uit. Wanneer deze functie is ingeschakeld, werkt deze in combinatie met het actieve hulpprogramma.
Notitie U kunt de weergavevolgorde van de ingebouwde knoppen niet wijzigen. De standaardweergavevolgorde is: Balpen, potlood, markeerstift, gum en liniaal. Aangepaste pennen worden toegevoegd aan de laatste standaardpen, aangepaste gereedschapsknoppen worden toegevoegd tussen de laatste penknop en de gumknop en aangepaste wisselknoppen worden toegevoegd na de liniaalknop. (Aangepaste knoppen worden toegevoegd in de volgorde waarin ze zijn opgegeven.)
Pen op maat
U kunt een aangepaste pen maken (geactiveerd via een aangepaste penknop) waarin u het kleurenpalet en de eigenschappen van de pentip definieert, zoals vorm, draaiing en grootte.
Aangepaste knop voor kalligrafische pen
In dit voorbeeld definiëren we een aangepaste pen met een brede tip waarmee eenvoudige kalligrafische pennenstreken mogelijk zijn. We passen ook de verzameling borstels aan in het palet dat wordt weergegeven op het uitklapmenu van de knop.
Code-behind
Eerst definiëren we onze aangepaste pen en geven we de tekenkenmerken in code-behind op. We verwijzen later naar deze aangepaste pen in XAML.
- Klik met de rechtermuisknop op het project in Solution Explorer en selecteer Toevoegen -> Nieuw item.
- Voeg onder Visual C# -> Code een nieuw klassebestand toe en noem het CalligraphicPen.cs.
- Vervang in Calligraphic.cs de standaardwaarde met behulp van blok door het volgende:
using System.Numerics;
using Windows.UI;
using Windows.UI.Input.Inking;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
- Geef op dat de klasse CalligraphicPen is afgeleid van InkToolbarCustomPen.
class CalligraphicPen : InkToolbarCustomPen
{
}
- Overschrijf CreateInkDrawingAttributesCore om uw eigen kwast- en pennenstreekgrootte op te geven.
class CalligraphicPen : InkToolbarCustomPen
{
protected override InkDrawingAttributes
CreateInkDrawingAttributesCore(Brush brush, double strokeWidth)
{
}
}
- Maak een InkDrawingAttributes-object en stel de pentipvorm, de draaiing van de punt, de lijngrootte en de inktkleur in.
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
Vervolgens voegen we de benodigde verwijzingen toe aan de aangepaste pen in MainPage.xaml.
- We declareren een resourcewoordenlijst voor lokale pagina's waarmee een verwijzing wordt gemaakt naar de aangepaste pen (
CalligraphicPen) die is gedefinieerd in CalligraphicPen.cs en een penseelverzameling die wordt ondersteund door de aangepaste pen (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>
- Daarna voegen we een InkToolbar toe met een kind-element InkToolbarCustomPenButton.
De aangepaste penknop bevat de twee statische bronverwijzingen die zijn gedeclareerd in de paginaresources: CalligraphicPen en CalligraphicPenPalette.
We geven ook het bereik op voor de schuifregelaar voor pennenstreken (MinStrokeWidth, MaxStrokeWidth en SelectedStrokeWidth), de geselecteerde borstel (SelectedBrushIndex) en het pictogram voor de aangepaste penknop (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>
Aangepaste wisselknop
U kunt een aangepaste wisselknop maken (geactiveerd via een aangepaste wisselknop) om de status van een door de app gedefinieerde functie in of uit te stellen. Wanneer deze functie is ingeschakeld, werkt deze in combinatie met het actieve hulpprogramma.
In dit voorbeeld definiëren we een aangepaste wisselknop waarmee handschrift met aanraakinvoer wordt ingeschakeld (standaard is aanraken niet ingeschakeld).
Opmerking
Als u inkt met aanraking wilt ondersteunen, raden we u aan deze in te schakelen met behulp van een CustomToggleButton, met het pictogram en de knopinfo die in dit voorbeeld zijn opgegeven.
Normaal gesproken wordt aanraakinvoer gebruikt voor directe manipulatie van een object of de gebruikersinterface van de app. Om de verschillen in gedrag te demonstreren wanneer handschrift aanraken is ingeschakeld, plaatsen we de InkCanvas in een ScrollViewer-container en stellen we de afmetingen van ScrollViewer in op kleiner dan de InkCanvas.
Wanneer de app wordt gestart, wordt alleen penschrift ondersteund en wordt aanraken gebruikt om het inktoppervlak te pannen of in te zoomen. Wanneer inkt aanraken is ingeschakeld, kan het inktoppervlak niet worden gepaneerd of ingezoomd via aanraakinvoer.
Opmerking
Zie handschriftbesturingselementen voor zowel InkCanvas als InkToolbar UX-richtlijnen. De volgende aanbevelingen zijn relevant voor dit voorbeeld:
- De InkToolbar en handschrift in het algemeen kunnen het beste worden ervaren door middel van een actieve pen. Tekenen met muis en aanraken kan echter, indien nodig, in uw app worden ondersteund.
- Als u inkt ondersteunt met aanraakinvoer, raden we aan het pictogram 'ED5F' uit het lettertype 'Segoe MLD2 Assets' voor de wisselknop te gebruiken, met als tooltip "Aanraakschrijven".
XAML
- Eerst declareren we een InkToolbarCustomToggleButton-element (toggleButton) met een Click-gebeurtenislistener waarmee de gebeurtenis-handler (Toggle_Custom) wordt opgegeven.
<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
In het vorige fragment hebben we een click event listener en handler (Toggle_Custom) gedeclareerd op de aangepaste schakelknop voor aanraken (toggleButton). Deze handler schakelt eenvoudigweg ondersteuning voor CoreInputDeviceTypes.Touch in via de eigenschap InputDeviceTypes van de InkPresenter.
We hebben ook een pictogram voor de knop opgegeven met behulp van het Element SymbolIcon en de markeringsextensie {x:Bind} die deze bindt aan een veld dat is gedefinieerd in het code-behind-bestand (TouchWritingIcon).
Het volgende codefragment bevat zowel de Click event handler als de definitie van 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;
}
}
}
}
Aangepast hulpprogramma
U kunt een aangepaste knop maken om een niet-penhulpmiddel op te roepen dat door uw app is gedefinieerd.
Standaard verwerkt een InkPresenter alle invoer als een pennenstreek of een wisstreek. Dit omvat invoer die is aangepast met een secundaire hardwarefunctie, zoals een knop op de pen, een rechtermuisknop of vergelijkbare middelen. InkPresenter kan echter worden geconfigureerd om specifieke invoer onbewerkt te laten, die vervolgens kan worden doorgegeven aan uw app voor aangepaste verwerking.
In dit voorbeeld definiëren we een aangepaste knop die, indien geselecteerd, ervoor zorgt dat volgende pennenstreken worden verwerkt en weergegeven als een selectie lasso (stippellijn) in plaats van inkt. Alle pennenstreken binnen de grenzen van het selectiegebied zijn ingesteld op Geselecteerd.
Opmerking
Zie handschriftbesturingselementen voor zowel InkCanvas als InkToolbar UX-richtlijnen. De volgende aanbeveling is relevant voor dit voorbeeld:
- Als u de optie voor pennenstreken biedt, raden we aan om het EF20-pictogram uit het lettertype 'Segoe MLD2 Assets' te gebruiken voor de knop van het hulpmiddel, met de hint 'Selectiehulpmiddel'.
XAML
Eerst declareren we een InkToolbarCustomToolButton element (customToolButton) met een Click-gebeurtenislistener die de eventhandler (customToolButton_Click) specificeert waar de selectie van pennenstreken wordt geconfigureerd. (We hebben ook een set knoppen toegevoegd voor het kopiëren, knippen en plakken van de pennenstreekselectie.)
We voegen ook een Canvas-element toe voor het tekenen van onze selectiestreek. Als u een afzonderlijke laag gebruikt om de selectiestreek te tekenen, zorgt u ervoor dat de InkCanvas en de inhoud ongewijzigd blijven.
<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
Vervolgens verwerken we de click-gebeurtenis voor de InkToolbarCustomToolButton in het bestand MainPage.xaml.cs code-behind.
Deze handler configureert de InkPresenter om niet-verwerkte invoer door te geven aan de app.
Zie de passthrough-invoer voor geavanceerde verwerking van peninteracties en Windows Ink in Windows-apps voor een gedetailleerdere stap door deze code.
We hebben ook een pictogram opgegeven voor de knop met behulp van het SymbolIcon-element en de markeringsextensie {x:Bind} waarmee deze wordt gekoppeld aan een veld dat is gedefinieerd in het code-behind-bestand (SelectIcon).
Het volgende codefragment bevat zowel de Click-gebeurtenis-handler als de definitie van 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);
}
}
}
}
Aangepaste inktweergave
Inktinvoer wordt standaard verwerkt op een achtergrondthread met lage latentie en 'nat' weergegeven terwijl deze wordt getekend. Wanneer de pennenstreek is voltooid (pen of vinger opgeheven of muisknop losgelaten), wordt de pennenstreek op de UI-thread verwerkt en 'droog' weergegeven op de InkCanvas-laag (boven de inhoud van de toepassing en ter vervanging van de natte inkt).
Met het inktplatform kunt u dit gedrag overschrijven en de inktervaring volledig aanpassen door de inktinvoer op maat te drogen.
Voor meer informatie over aangepaste droogfuncties, zie Peninteracties en Windows Ink in Windows-apps.
Opmerking
Aangepast drogen en de InkToolbar
Als uw app het standaardgedrag voor inktweergave van De InkPresenter overschrijft met een aangepaste droogimplementatie, zijn de gerenderde pennenstreken niet meer beschikbaar voor de InkToolbar en werken de ingebouwde wisopdrachten van de InkToolbar niet zoals verwacht. Als u gumfunctie wilt bieden, moet u alle pointerevents afhandelen, raakdetectie uitvoeren op elke pennenstreek en de ingebouwde opdracht 'Alle inkt wissen' overschrijven.
Verwante artikelen
Onderwerpvoorbeelden
- Voorbeeld van de locatie en oriëntatie van de inktwerkbalk (basis)
- Voorbeeld van locatie en oriëntatie van de inktwerkbalk (dynamisch)
Andere voorbeelden
Windows developer