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.
Important
InkCanvas, InkToolbaren InkPresenter zijn experimentele API's. Inktondersteuning is toegevoegd in Windows App SDK 2.4.1-experimental. In dit artikel wordt Windows App SDK 2.5.4-experimental beschreven, dat heeft gewijzigd hoe u een InkToolbar verbindt. Deze API's zijn niet beschikbaar in het stabiele kanaal. Ze kunnen in een toekomstige release worden gewijzigd of verwijderd. Gebruik ze niet in productie-apps.
Gebruik het experimentele besturingselement InkCanvas waarmee gebruikers met inkt kunnen tekenen met een pen, muis of via aanraking. Voeg een InkToolbar toe om gebruikers een balpen, potlood, markeerstift en gum te geven, met opties voor kleur en grootte. Elk canvas heeft een InkPresenter object waarmee inktinvoer wordt verzameld en weergegeven. De InkStrokeContainer van de presentator slaat de pennenstreken op, zodat u inkt in code kunt opslaan, laden, kopiëren en maken.
Als u de besturingselementen wilt proberen, installeert u het Windows App SDK 2.5.4-experimental package en de bijbehorende runtime. Zie Meest recente Windows App SDK-downloads voor downloadkoppelingen en installatiegegevens.
Is dit de juiste controle?
Gebruik een inktcanvas wanneer gebruikers het volgende moeten doen:
- Maak handgeschreven notities of annoteer inhoud.
- Schets, teken diagrammen of onderteken je naam.
- Maak inhoud uit de vrije hand die uw app opslaat en die gebruikers later kunnen bewerken.
De experimentele inkt-API's bevatten geen handschrift- of vormherkenning. Als u tekst wilt verzamelen, gebruikt u een tekstvak.
Als u inken in een productie-app nodig hebt, raadpleegt u Bekende controle-hiaten voor de status van deze besturingselementen in het stabiele kanaal en voor alternatieven.
Begrijp het inktmodel
De ink-API's werken samen:
| API | Role |
|---|---|
InkCanvas |
Het XAML-element dat inkt weergeeft en inktinvoer ontvangt. De InkPresenter eigenschap retourneert de presenter voor het canvas. |
InkPresenter |
Verzamelt inktinvoer, rendert pennenstreken en bevat de invoerinstellingen en standaardtekeningkenmerken. U kunt niet zelf een InkPresenter maken. Download het van InkCanvas.InkPresenter. |
InkStrokeContainer |
Slaat streken op. Gebruik deze om inkt op te slaan, te openen, te selecteren, te kopiëren en te plakken. Haal het op via InkPresenter.StrokeContainer. |
InkToolbar |
Een optionele werkbalk waarmee gebruikers een pen, potlood, markeerstift of gum kunnen kiezen en inktkleur en -grootte kunnen wijzigen. |
InkCanvas heeft geen Background eigenschap. Als u het tekengebied een achtergrond en een rand wilt geven, plaatst u het canvas in een container, zoals een Border, en stelt u de grootte van de container in. De standaardkleur van inkt is zwart, dus in de voorbeelden in dit artikel wordt een witte achtergrond gebruikt.
Verschillende van deze typen hebben dezelfde namen als typen in de Windows Runtime-naamruimte Windows.UI.Input.Inking, zoals InkPresenter, InkStrokeContainer, en InkHighContrastAdjustment. De inktbedieningselementen gebruiken de Microsoft.UI.Xaml.Controls versies. Stroken en tekenkenmerken maken nog steeds gebruik van Windows Runtime typen, zoals InkStroke, InkDrawingAttributesen InkStrokeBuilder. Als u zowel naamruimten importeert als een dubbelzinnige naam gebruikt, rapporteert de C#-compiler fout CS0104.
In de voorbeelden in dit artikel wordt Microsoft.UI.Xaml.Controls geïmporteerd en worden aliasrichtlijnen gebruikt voor de Windows.UI.Input.Inking-typen die ze nodig hebben:
using Microsoft.UI.Xaml.Controls;
using InkDrawingAttributes = Windows.UI.Input.Inking.InkDrawingAttributes;
using InkStroke = Windows.UI.Input.Inking.InkStroke;
U kunt zowel naamruimten importeren als volledig gekwalificeerde namen gebruiken voor de dubbelzinnige typen, zoals in het WinUI 3 Gallery-voorbeeld.
InkPresenter biedt ook API's op lager niveau die in dit artikel niet worden behandeld:
-
StrokeInputgenereert gebeurtenissen wanneer een pennenstreek begint, doorgaat, eindigt of wordt geannuleerd. -
UnprocessedInputgenereert aanwijzergebeurtenissen voor invoer die de presenter niet als inkt verwerkt. -
InputConfigurationstelt in of het presentatieprogramma invoer verwerkt van de gum van een pen en de primaire barrelknop. -
InputProcessingConfigurationstelt in of de invoer inkt tekent, inkt wist of niet wordt verwerkt en hoe de presentator invoer via slepen met de rechtermuisknop verwerkt. -
ActivateCustomDryinggeeft eenInkSynchronizerterug voor apps die doorgevoerde inkt zelf weergeven.
Stel uw project in
De inkt-API's zijn gemarkeerd als experimenteel. Wanneer u deze gebruikt in een C#-project, rapporteert de C#-compiler waarschuwing CS8305 en de XAML-compiler waarschuwingen WMC1501. Als in uw project waarschuwingen als fouten worden behandeld, stoppen deze waarschuwingen de build.
Nadat u hebt besloten om de experimentele API's te gebruiken, kunt u deze waarschuwingen onderdrukken. Voeg de volgende eigenschappen toe aan het C#-projectbestand (.csproj):
<PropertyGroup>
<NoWarn>$(NoWarn);CS8305</NoWarn>
<MSBuildWarningsAsMessages>$(MSBuildWarningsAsMessages);WMC1501</MSBuildWarningsAsMessages>
</PropertyGroup>
In de voorbeelden in dit artikel wordt C# gebruikt. Elk volledig voorbeeld toont de XAML voor een pagina en de code-behind-klasse van de pagina, MainPage.
Inktgebied maken
![]()
De WinUI 3 Gallery-app bevat interactieve voorbeelden van WinUI-besturingselementen en -functies. Haal de app op uit de Microsoft Store of blader door de broncode op GitHub.
In het volgende voorbeeld wordt een canvas in een witte Border geplaatst. De code-behind stelt de invoerapparaattypen in, zodat gebruikers kunnen tekenen met een pen, muis of touchinvoer.
<Border
Height="300"
Background="White"
BorderBrush="{ThemeResource SystemControlForegroundChromeHighBrush}"
BorderThickness="1">
<InkCanvas x:Name="inkCanvas" AutomationProperties.Name="Drawing surface" />
</Border>
using Microsoft.UI.Xaml.Controls;
using Windows.UI.Core;
public sealed partial class MainPage : Page
{
public MainPage()
{
InitializeComponent();
// Mouse input doesn't draw ink by default. Choose every device type that can draw ink.
inkCanvas.InkPresenter.InputDeviceTypes =
CoreInputDeviceTypes.Pen | CoreInputDeviceTypes.Mouse | CoreInputDeviceTypes.Touch;
}
}
Om ze kort te houden, wordt deze code in enkele latere voorbeelden niet herhaald. Stel InputDeviceTypes in op elke pagina waar gebruikers met een muis tekenen.
Een inktwerkbalk koppelen
Plaats een InkToolbar in de buurt van het canvas en stel de eigenschap TargetInkCanvas ervan in om de twee te verbinden:
<StackPanel Spacing="8">
<InkToolbar
x:Name="inkToolbar"
AutomationProperties.Name="Drawing tools"
TargetInkCanvas="{x:Bind inkCanvas}" />
<Border
Height="300"
Background="White"
BorderBrush="{ThemeResource SystemControlForegroundChromeHighBrush}"
BorderThickness="1">
<InkCanvas x:Name="inkCanvas" AutomationProperties.Name="Drawing surface" />
</Border>
</StackPanel>
Vanaf Windows App SDK 2.5.4-experimenteel kunt u in plaats daarvan een werkbalk rechtstreeks verbinden met een InkPresenter door de TargetInkPresenter eigenschap in te stellen. Stel dit in code in:
inkToolbar.TargetInkPresenter = inkCanvas.InkPresenter;
U kunt deze ook instellen in XAML: TargetInkPresenter="{x:Bind inkCanvas.InkPresenter}". Stel slechts één van de twee doeleigenschappen in.
Op de werkbalk worden standaard knoppen voor balpen, potlood, markeerstift, gum en stencil (liniaal) weergegeven. Zie De inktwerkbalk aanpassen als u wilt wijzigen welke knoppen worden weergegeven.
Invoerapparaten kiezen
De InputDeviceTypes eigenschap maakt gebruik van de CoreInputDeviceTypes opsomming vlaggen uit de Windows.UI.Core naamruimte. Met muisinvoer wordt standaard geen inkt getekend. Waarden combineren om te kiezen welke apparaten inkt gebruiken:
// Add mouse input and keep the other device types.
inkCanvas.InkPresenter.InputDeviceTypes |= CoreInputDeviceTypes.Mouse;
// Stop accepting ink from touch input.
inkCanvas.InkPresenter.InputDeviceTypes &= ~CoreInputDeviceTypes.Touch;
// Check whether pen input is enabled.
bool isPenEnabled = inkCanvas.InkPresenter.InputDeviceTypes.HasFlag(CoreInputDeviceTypes.Pen);
Als u wilt stoppen met het verzamelen van inkt vanaf elk apparaat, bijvoorbeeld om een tekening weer te geven die gebruikers niet kunnen wijzigen, stelt u IsInputEnabled in op false:
inkCanvas.InkPresenter.IsInputEnabled = false;
Als u wilt dat gebruikers een invoerapparaat in- of uitschakelen vanaf de werkbalk, raadpleegt u Een aangepaste wisselknop toevoegen.
Tekenkenmerken instellen
Tekenkenmerken, zoals kleur, grootte en vorm van pentip, bepalen hoe streken eruitzien. Ze gebruiken de Windows Runtime InkDrawingAttributes klasse. Als u de kenmerken voor nieuwe streken wilt wijzigen, roept u CopyDefaultDrawingAttributes aan, wijzigt u de kopie en geeft u deze door aan UpdateDefaultDrawingAttributes:
InkDrawingAttributes attributes = inkCanvas.InkPresenter.CopyDefaultDrawingAttributes();
attributes.Color = Colors.DarkBlue;
attributes.Size = new Size(4, 4);
inkCanvas.InkPresenter.UpdateDefaultDrawingAttributes(attributes);
Colors is in de Microsoft.UI naamruimte, en Size bevindt zich in de Windows.Foundation naamruimte. De nieuwe attributen zijn van toepassing op pennenstreken die gebruikers na de oproep tekenen. Bestaande lijnen behouden hun attributen.
Wanneer u een InkToolbar aansluit, bepalen het actieve hulpprogramma en de kleur- en grootte-instellingen de tekenkenmerken. Als u de huidige kenmerken wilt lezen, gebruikt u de eigenschap van de werkbalk InkDrawingAttributes.
Penvoorinstellingen maken
Als u geen werkbalk gebruikt, kunt u uw eigen penvoorinstellingen aanbieden. In het volgende voorbeeld worden ballpoint-, potlood-, markeerstift- of kalligrafiekenmerken toegepast wanneer de gebruiker een vooraf ingestelde waarde selecteert of de grootte wijzigt.
<StackPanel Spacing="12">
<RadioButtons
x:Name="presetButtons"
Header="Pen preset"
MaxColumns="4"
SelectedIndex="0"
SelectionChanged="PresetButtons_SelectionChanged">
<x:String>Ballpoint</x:String>
<x:String>Pencil</x:String>
<x:String>Highlighter</x:String>
<x:String>Calligraphy</x:String>
</RadioButtons>
<Slider
x:Name="sizeSlider"
Width="240"
HorizontalAlignment="Left"
Header="Size"
Maximum="16"
Minimum="1"
Value="4"
ValueChanged="SizeSlider_ValueChanged" />
<Border
Width="480"
Height="280"
HorizontalAlignment="Left"
Background="White"
BorderBrush="{ThemeResource SystemControlForegroundChromeHighBrush}"
BorderThickness="1">
<InkCanvas x:Name="inkCanvas" AutomationProperties.Name="Drawing surface" />
</Border>
</StackPanel>
using System;
using System.Numerics;
using Microsoft.UI;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Windows.Foundation;
using Windows.UI.Core;
using InkDrawingAttributes = Windows.UI.Input.Inking.InkDrawingAttributes;
using PenTipShape = Windows.UI.Input.Inking.PenTipShape;
public sealed partial class MainPage : Page
{
public MainPage()
{
InitializeComponent();
inkCanvas.InkPresenter.InputDeviceTypes =
CoreInputDeviceTypes.Pen | CoreInputDeviceTypes.Mouse | CoreInputDeviceTypes.Touch;
ApplyPreset();
}
private void PresetButtons_SelectionChanged(object sender, SelectionChangedEventArgs e) => ApplyPreset();
private void SizeSlider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e) => ApplyPreset();
private void ApplyPreset()
{
// SelectionChanged and ValueChanged can occur while the page is still loading.
if (inkCanvas is null || presetButtons is null || sizeSlider is null)
{
return;
}
double size = sizeSlider.Value;
InkDrawingAttributes attributes;
switch (presetButtons.SelectedItem as string)
{
case "Pencil":
// CreateForPencil returns attributes for pencil-style strokes.
attributes = InkDrawingAttributes.CreateForPencil();
attributes.Color = Colors.DimGray;
attributes.Size = new Size(size, size);
break;
case "Highlighter":
attributes = new InkDrawingAttributes
{
Color = Colors.Yellow,
DrawAsHighlighter = true,
PenTip = PenTipShape.Rectangle,
Size = new Size(size, size * 3),
};
break;
case "Calligraphy":
attributes = new InkDrawingAttributes
{
Color = Colors.DarkBlue,
PenTip = PenTipShape.Rectangle,
Size = new Size(Math.Max(1, size / 2), size * 2),
// Rotate the nib 45 degrees so the stroke width changes with the stroke direction.
PenTipTransform = Matrix3x2.CreateRotation(MathF.PI / 4),
};
break;
default:
attributes = new InkDrawingAttributes
{
Color = Colors.Black,
PenTip = PenTipShape.Circle,
Size = new Size(size, size),
};
break;
}
// The new attributes apply to strokes that the user draws after this call.
inkCanvas.InkPresenter.UpdateDefaultDrawingAttributes(attributes);
}
}
-
InkDrawingAttributes.CreateForPencilgeeft kenmerken voor potloodstreken terug. DeKindeigenschap is alleen-lezen, dus gebruik deze methode om potloodattributen te maken. -
DrawAsHighlightergeeft de lijn weer als een markeerlaag. -
PenTipstelt de vorm van de pentip in enPenTipTransformdraait of schaalt deze. Een gedraaide rechthoekige tip produceert kalligrafische streken.
Reageren op inktwijzigingen
De presentator activeert StrokesCollected nadat een gebruiker pennenstreken tekent en StrokesErased nadat een gebruiker deze heeft gewist. De Strokes eigenschap van de argumenten van elke gebeurtenis bevat de betrokken streken. Met de volgende code blijft het aantal pennenstreken up-to-date in een TextBlock met de naam strokeCountText:
inkCanvas.InkPresenter.StrokesCollected += (sender, args) => UpdateStrokeCount();
inkCanvas.InkPresenter.StrokesErased += (sender, args) => UpdateStrokeCount();
private void UpdateStrokeCount()
{
int count = inkCanvas.InkPresenter.StrokeContainer.GetStrokes().Count;
strokeCountText.Text = $"{count} strokes";
}
Deze gebeurtenissen treden op wanneer gebruikers met inkt tekenen of wissen. Wanneer u strokes in code wijzigt, bijvoorbeeld met Clear, LoadAsync of AddStroke, werkt u uw gebruikersinterface bij na de aanroep.
Inkt opslaan en laden
InkStrokeContainer slaat inkt op in Ink Serialized Format (ISF). Als u wilt kiezen hoe de gegevens worden opgeslagen, geeft u een InkPersistenceFormat waarde door aan SaveAsync:
| Format | Uitvoer |
|---|---|
GifWithEmbeddedIsf |
Een GIF-afbeelding die de inktgegevens bevat. Afbeeldingsviewers kunnen het bestand weergeven en uw app kan de digitale inkt opnieuw laden om te bewerken. |
Isf |
Alleen inktgegevens, zonder een afbeelding. Dit is het meest compacte formaat. |
Voeg de volgende methoden toe aan de code-behind van een pagina die een InkCanvas met de naam inkCanvas bevat.
SaveInkAsync schrijft de inkt naar een bestand en LoadInkAsync vervangt de inkt op het canvas door de inkt uit een bestand.
LoadAsync verwijdert de bestaande pennenstreken voordat de geladen pennenstreken worden toegevoegd, dus u hoeft Clear niet eerst aan te roepen.
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.UI.Xaml.Controls;
using Windows.Storage.Streams;
using InkPersistenceFormat = Windows.UI.Input.Inking.InkPersistenceFormat;
public sealed partial class MainPage : Page
{
private async Task SaveInkAsync(string path)
{
InkStrokeContainer container = inkCanvas.InkPresenter.StrokeContainer;
// File.Create replaces any existing file, so the file contains only the new ink.
using FileStream fileStream = File.Create(path);
using IOutputStream output = fileStream.AsOutputStream();
// GifWithEmbeddedIsf writes a GIF image that also contains the editable ink data.
await container.SaveAsync(output, InkPersistenceFormat.GifWithEmbeddedIsf);
await output.FlushAsync();
}
private async Task LoadInkAsync(string path)
{
InkStrokeContainer container = inkCanvas.InkPresenter.StrokeContainer;
using FileStream fileStream = File.OpenRead(path);
using IInputStream input = fileStream.AsInputStream();
// LoadAsync removes the current strokes before it adds the loaded strokes.
await container.LoadAsync(input);
}
}
AsOutputStream en AsInputStream converteren .NET streams naar de Windows Runtime stroomtypen die SaveAsync en LoadAsync gebruiken. Om deze Windows Runtime-methoden te kunnen awaiten, heeft het bestand de using System;-richtlijn nodig. Zonder dit meldt de compiler fout CS4036.
Als u gebruikers een bestand wilt laten kiezen, gebruikt u de Windows App SDK bestandskiezers, die het pad van het geselecteerde bestand retourneren. Zie Een bestand opslaan met een Windows App SDK picker en Bestanden en mappen openen met Windows App SDK pickers voor meer informatie.
Als u inkt in het geheugen wilt bewaren, bijvoorbeeld om deze later in dezelfde sessie te herstellen, slaat u deze op in een InMemoryRandomAccessStream. Geef het resultaat van de stream van GetOutputStreamAt(0) door aan SaveAsync, en geef het resultaat ervan van GetInputStreamAt(0) door aan LoadAsync. In het WinUI 3 Gallery-voorbeeld wordt deze methode gebruikt.
Kopieer en plak inkt
InkStrokeContainer kan pennenstreken naar het klembord kopiëren en er inkt uit invoegen.
CopySelectedToClipboard kopieert alleen geselecteerde pennenstreken, dus in het volgende voorbeeld wordt elke pennenstreek op het linkercanvas geselecteerd voordat ze worden gekopieerd.
CanPasteFromClipboard controleert of het klembord inkt bevat.
PasteFromClipboard voegt de inkt toe op de positie die u doorgeeft en retourneert de begrenzingsrechthoek van het gebied dat is gewijzigd.
<StackPanel Spacing="12">
<StackPanel Orientation="Horizontal" Spacing="8">
<Button Click="CopyButton_Click" Content="Copy left canvas" />
<Button
x:Name="pasteButton"
Click="PasteButton_Click"
Content="Paste into right canvas"
IsEnabled="False" />
</StackPanel>
<StackPanel Orientation="Horizontal" Spacing="12">
<Border
Width="300"
Height="220"
Background="White"
BorderBrush="{ThemeResource SystemControlForegroundChromeHighBrush}"
BorderThickness="1">
<InkCanvas x:Name="sourceCanvas" AutomationProperties.Name="Source drawing surface" />
</Border>
<Border
Width="300"
Height="220"
Background="White"
BorderBrush="{ThemeResource SystemControlForegroundChromeHighBrush}"
BorderThickness="1">
<InkCanvas x:Name="targetCanvas" AutomationProperties.Name="Target drawing surface" />
</Border>
</StackPanel>
<TextBlock x:Name="statusText" Text="Draw on the left canvas, then copy it." TextWrapping="Wrap" />
</StackPanel>
using System.Collections.Generic;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Windows.Foundation;
using Windows.UI.Core;
using InkStroke = Windows.UI.Input.Inking.InkStroke;
public sealed partial class MainPage : Page
{
public MainPage()
{
InitializeComponent();
foreach (InkCanvas canvas in new[] { sourceCanvas, targetCanvas })
{
canvas.InkPresenter.InputDeviceTypes =
CoreInputDeviceTypes.Pen | CoreInputDeviceTypes.Mouse | CoreInputDeviceTypes.Touch;
}
}
private void CopyButton_Click(object sender, RoutedEventArgs e)
{
InkStrokeContainer source = sourceCanvas.InkPresenter.StrokeContainer;
IReadOnlyList<InkStroke> strokes = source.GetStrokes();
if (strokes.Count == 0)
{
statusText.Text = "Draw on the left canvas first.";
return;
}
// CopySelectedToClipboard copies only selected strokes, so select all strokes first.
foreach (InkStroke stroke in strokes)
{
stroke.Selected = true;
}
source.CopySelectedToClipboard();
foreach (InkStroke stroke in strokes)
{
stroke.Selected = false;
}
pasteButton.IsEnabled = targetCanvas.InkPresenter.StrokeContainer.CanPasteFromClipboard();
statusText.Text = $"Copied {strokes.Count} stroke(s) to the clipboard.";
}
private void PasteButton_Click(object sender, RoutedEventArgs e)
{
InkStrokeContainer target = targetCanvas.InkPresenter.StrokeContainer;
if (!target.CanPasteFromClipboard())
{
statusText.Text = "The clipboard doesn't contain ink.";
return;
}
// Place the pasted ink near the upper-left corner of the target canvas.
Rect pasted = target.PasteFromClipboard(new Point(16, 16));
statusText.Text = $"Pasted ink into a {pasted.Width:0} x {pasted.Height:0} area.";
}
}
Als u met een aantal streken wilt werken, stelt u de Selected-eigenschap in van elke gewenste streek, of roept u SelectWithLine of SelectWithPolyLine aan. Als u de geselecteerde pennenstreken wilt verwijderen of verplaatsen, gebruikt u DeleteSelected of MoveSelected.
Lijnen maken in code
Gebruik de Windows Runtime-klasse InkStrokeBuilder om pennenstreken te maken op basis van punten en voeg ze toe aan het canvas met AddStroke. In het volgende voorbeeld worden een ster en een handtekeningregel toegevoegd.
<StackPanel Spacing="12">
<StackPanel Orientation="Horizontal" Spacing="8">
<Button Click="AddStarButton_Click" Content="Add star" />
<Button Click="AddSignatureLineButton_Click" Content="Add signature line" />
<Button Click="ClearButton_Click" Content="Clear" />
</StackPanel>
<Border
Width="480"
Height="280"
HorizontalAlignment="Left"
Background="White"
BorderBrush="{ThemeResource SystemControlForegroundChromeHighBrush}"
BorderThickness="1">
<InkCanvas x:Name="inkCanvas" AutomationProperties.Name="Drawing surface" />
</Border>
</StackPanel>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Microsoft.UI;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Windows.Foundation;
using Windows.UI;
using InkDrawingAttributes = Windows.UI.Input.Inking.InkDrawingAttributes;
using InkPoint = Windows.UI.Input.Inking.InkPoint;
using InkStroke = Windows.UI.Input.Inking.InkStroke;
using InkStrokeBuilder = Windows.UI.Input.Inking.InkStrokeBuilder;
public sealed partial class MainPage : Page
{
public MainPage()
{
InitializeComponent();
}
private void AddStarButton_Click(object sender, RoutedEventArgs e)
{
// Alternate between outer and inner points to draw a five-pointed star.
Point center = new(inkCanvas.ActualWidth / 2, 90);
List<Point> points = new();
for (int i = 0; i <= 10; i++)
{
double radius = i % 2 == 0 ? 70 : 28;
double angle = -Math.PI / 2 + i * Math.PI / 5;
points.Add(new Point(center.X + radius * Math.Cos(angle), center.Y + radius * Math.Sin(angle)));
}
AddStroke(points, Colors.Goldenrod, 4);
}
private void AddSignatureLineButton_Click(object sender, RoutedEventArgs e)
{
double left = 40;
double right = inkCanvas.ActualWidth - 40;
double baseline = inkCanvas.ActualHeight - 40;
AddStroke(new[] { new Point(left, baseline), new Point(right, baseline) }, Colors.Gray, 2);
AddStroke(new[] { new Point(left, baseline - 28), new Point(left + 18, baseline - 10) }, Colors.Gray, 2);
AddStroke(new[] { new Point(left + 18, baseline - 28), new Point(left, baseline - 10) }, Colors.Gray, 2);
}
private void ClearButton_Click(object sender, RoutedEventArgs e)
{
inkCanvas.InkPresenter.StrokeContainer.Clear();
}
private void AddStroke(IEnumerable<Point> points, Color color, double size)
{
InkStrokeBuilder builder = new();
builder.SetDefaultDrawingAttributes(new InkDrawingAttributes
{
Color = color,
Size = new Size(size, size),
// Keep straight segments and sharp corners instead of smoothing them into curves.
FitToCurve = false,
});
// Give every point the same pressure so that the stroke has a uniform width.
IEnumerable<InkPoint> inkPoints = points.Select(point => new InkPoint(point, 0.5f));
InkStroke stroke = builder.CreateStrokeFromInkPoints(inkPoints, Matrix3x2.Identity);
inkCanvas.InkPresenter.StrokeContainer.AddStroke(stroke);
}
}
-
CreateStrokeFromInkPointsmaakt een pennenstreek op basis vanInkPointwaarden. Elk punt combineert een positie op het canvas met een drukwaarde. - In de Windows Runtime-documentatie wordt
CreateStrokeaanbevolen in plaats vanCreateStrokeFromInkPointsvoor pennenstreken die u aan een inktpresentator toevoegt. - Wanneer
FitToCurveisfalse, gebruikt de contour rechte segmenten tussen punten in plaats van curven.
Een lijn kan slechts tot één container behoren. Als u pennenstreken naar een ander canvas wilt kopiëren, voegt u klonen van de pennenstreken toe:
private void CopyStrokesTo(InkCanvas target)
{
foreach (InkStroke stroke in inkCanvas.InkPresenter.StrokeContainer.GetStrokes())
{
target.InkPresenter.StrokeContainer.AddStroke(stroke.Clone());
}
}
De inktwerkbalk aanpassen
Kies de oorspronkelijke bedieningselementen
De InitialControls eigenschap bepaalt welke ingebouwde knoppen door de werkbalk worden aangemaakt:
| Value | Ingebouwde knoppen |
|---|---|
All (standaard) |
Balpen, potlood, markeerstift, gum en sjabloon (liniaal) |
PensOnly |
Balpen, potlood en markeerstift |
AllExceptPens |
Gummetje en sjabloon (liniaal) |
None |
None. Definieer de gewenste knoppen als onderliggende elementen van de werkbalk. |
In het volgende voorbeeld worden dezelfde vier knoppen als in het WinUI 3 Gallery-voorbeeld gedeclareerd, krijgt elke knop een toegankelijke naam en wordt de balpen geselecteerd wanneer de werkbalk wordt geladen:
<StackPanel Spacing="8">
<InkToolbar
x:Name="inkToolbar"
AutomationProperties.Name="Drawing tools"
InitialControls="None"
TargetInkCanvas="{x:Bind inkCanvas}">
<InkToolbarBallpointPenButton x:Name="ballpointButton" AutomationProperties.Name="Ballpoint pen" />
<InkToolbarPencilButton AutomationProperties.Name="Pencil" />
<InkToolbarHighlighterButton AutomationProperties.Name="Highlighter" />
<InkToolbarEraserButton AutomationProperties.Name="Eraser" />
</InkToolbar>
<Border
Height="300"
Background="White"
BorderBrush="{ThemeResource SystemControlForegroundChromeHighBrush}"
BorderThickness="1">
<InkCanvas x:Name="inkCanvas" AutomationProperties.Name="Drawing surface" />
</Border>
</StackPanel>
using Microsoft.UI.Xaml.Controls;
public sealed partial class MainPage : Page
{
public MainPage()
{
InitializeComponent();
// Select a starting tool after the toolbar loads.
inkToolbar.Loaded += (sender, args) =>
{
if (inkToolbar.ActiveTool is null)
{
inkToolbar.ActiveTool = ballpointButton;
}
};
}
}
Als u een opdracht wilt weergeven waarmee alle inkt wordt gewist, stelt u de IsClearAllVisible-eigenschap van de gumknop in op true. De werkbalk genereert de EraseAllClicked gebeurtenis wanneer de gebruiker de opdracht selecteert.
De kleuren en lijndiktes van een pen aanpassen
Elke penknop heeft een Palette selectie penselen en lijnbreedte-instellingen. Stel Palette in de code in. Zie Bekende beperkingenvoor meer informatie. In het volgende voorbeeld wordt het palet van een balpen vervangen door vier merkkleuren, de breedte van de lijn beperkt en worden de kenmerken van de actieve pen weergegeven.
<StackPanel Spacing="12">
<InkToolbar
x:Name="inkToolbar"
AutomationProperties.Name="Drawing tools"
InitialControls="AllExceptPens"
TargetInkCanvas="{x:Bind inkCanvas}">
<InkToolbarBallpointPenButton
x:Name="brandPen"
AutomationProperties.Name="Brand pen"
MaxStrokeWidth="16"
MinStrokeWidth="2"
SelectedStrokeWidth="6" />
</InkToolbar>
<RadioButtons
x:Name="colorButtons"
Header="Pen color"
MaxColumns="4"
SelectedIndex="0"
SelectionChanged="ColorButtons_SelectionChanged">
<x:String>Blue</x:String>
<x:String>Green</x:String>
<x:String>Orange</x:String>
<x:String>Purple</x:String>
</RadioButtons>
<TextBlock x:Name="penInfo" />
<Border
Width="480"
Height="240"
HorizontalAlignment="Left"
Background="White"
BorderBrush="{ThemeResource SystemControlForegroundChromeHighBrush}"
BorderThickness="1">
<InkCanvas x:Name="inkCanvas" AutomationProperties.Name="Drawing surface" />
</Border>
</StackPanel>
using System.Linq;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
using Windows.UI;
public sealed partial class MainPage : Page
{
private static readonly Color[] BrandColors =
{
Color.FromArgb(0xFF, 0x00, 0x78, 0xD4), // Blue
Color.FromArgb(0xFF, 0x10, 0x7C, 0x10), // Green
Color.FromArgb(0xFF, 0xD8, 0x3B, 0x01), // Orange
Color.FromArgb(0xFF, 0x5C, 0x2D, 0x91), // Purple
};
public MainPage()
{
InitializeComponent();
// Replace the pen's default palette and select the first color.
brandPen.Palette = BrandColors.Select(color => (Brush)new SolidColorBrush(color)).ToList();
brandPen.SelectedBrushIndex = 0;
inkToolbar.InkDrawingAttributesChanged += (sender, args) => ShowPenInfo();
// The toolbar sets up its buttons when it loads, so select the starting tool then.
inkToolbar.Loaded += (sender, args) =>
{
inkToolbar.ActiveTool = brandPen;
ShowPenInfo();
};
}
private void ColorButtons_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// SelectionChanged can occur while the page is still loading.
if (brandPen is null || colorButtons is null || penInfo is null || colorButtons.SelectedIndex < 0)
{
return;
}
// SelectedBrushIndex selects an entry in Palette, like choosing a color in the pen flyout.
brandPen.SelectedBrushIndex = colorButtons.SelectedIndex;
inkToolbar.ActiveTool = brandPen;
ShowPenInfo();
}
private void ShowPenInfo()
{
// InkDrawingAttributes describes the ink that the active tool draws.
if (inkToolbar.InkDrawingAttributes is { } attributes)
{
penInfo.Text = $"Color {attributes.Color}, width {attributes.Size.Width:0} (range {brandPen.MinStrokeWidth:0}-{brandPen.MaxStrokeWidth:0})";
}
}
}
SelectedBrushIndex selecteert een kleur uit Palette.
SelectedStrokeWidth, MinStrokeWidthen MaxStrokeWidth stel de huidige lijnbreedte en het bereik in waaruit gebruikers kunnen kiezen. De werkbalk activeert InkDrawingAttributesChanged wanneer de kenmerken van het actieve hulpprogramma worden gewijzigd.
Selecteer het actieve gereedschap
Stel ActiveTool in om een tool te selecteren en gebruik ActiveToolChanged om te reageren wanneer de gebruiker een andere tool selecteert.
GetToolButton retourneert een ingebouwde werkbalkknop van het soort dat u doorgeeft. De ingebouwde knoppen bestaan mogelijk niet totdat de werkbalk wordt geladen. Selecteer daarom een startgereedschap in de gebeurtenis-handler van de werkbalk Loaded.
<StackPanel Spacing="12">
<InkToolbar
x:Name="inkToolbar"
AutomationProperties.Name="Drawing tools"
TargetInkCanvas="{x:Bind inkCanvas}" />
<TextBlock x:Name="toolInfo" />
<Border
Width="480"
Height="280"
HorizontalAlignment="Left"
Background="White"
BorderBrush="{ThemeResource SystemControlForegroundChromeHighBrush}"
BorderThickness="1">
<InkCanvas x:Name="inkCanvas" AutomationProperties.Name="Drawing surface" />
</Border>
</StackPanel>
using Microsoft.UI.Xaml.Controls;
public sealed partial class MainPage : Page
{
public MainPage()
{
InitializeComponent();
inkToolbar.ActiveToolChanged += (sender, args) => ShowToolInfo();
inkToolbar.InkDrawingAttributesChanged += (sender, args) => ShowToolInfo();
// The toolbar creates its built-in buttons when it loads, so select the starting tool then.
inkToolbar.Loaded += (sender, args) =>
{
inkToolbar.ActiveTool = inkToolbar.GetToolButton(InkToolbarTool.Pencil);
ShowToolInfo();
};
}
private void ShowToolInfo()
{
if (inkToolbar.ActiveTool is not { } tool)
{
toolInfo.Text = "No active tool";
return;
}
toolInfo.Text = inkToolbar.InkDrawingAttributes is { } attributes
? $"{tool.ToolKind}: {attributes.Kind} ink, color {attributes.Color}, size {attributes.Size.Width:0}"
: $"{tool.ToolKind}";
}
}
De afdrukstand wijzigen
Als u de werkbalk verticaal wilt weergeven, bijvoorbeeld naast het canvas, stelt u Orientation in op Vertical:
<Grid HorizontalAlignment="Left" ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<InkToolbar
VerticalAlignment="Top"
AutomationProperties.Name="Drawing tools"
Orientation="Vertical"
TargetInkCanvas="{x:Bind inkCanvas}" />
<Border
Grid.Column="1"
Width="440"
Height="320"
VerticalAlignment="Top"
Background="White"
BorderBrush="{ThemeResource SystemControlForegroundChromeHighBrush}"
BorderThickness="1">
<InkCanvas x:Name="inkCanvas" AutomationProperties.Name="Drawing surface" />
</Border>
</Grid>
Met ButtonFlyoutPlacement de eigenschap wordt ingesteld waar flyouts van knoppen worden geopend ten opzichte van de werkbalk. Met de standaardwaarde Autokan de werkbalk de positie kiezen.
Een aangepaste wisselknop toevoegen
Gebruik een InkToolbarCustomToggleButton om een instelling toe te voegen die gebruikers in- en uitschakelen vanaf de werkbalk. In het volgende voorbeeld wordt een wisselknop toegevoegd waarmee aanraakinvoer wordt bestuurd. Met pen- en muisinvoer wordt altijd inkt getekend.
<StackPanel Spacing="12">
<InkToolbar AutomationProperties.Name="Drawing tools" TargetInkCanvas="{x:Bind inkCanvas}">
<InkToolbarCustomToggleButton
x:Name="touchWritingToggle"
AutomationProperties.Name="Touch writing"
Checked="TouchWritingToggle_Changed"
ToolTipService.ToolTip="Touch writing"
Unchecked="TouchWritingToggle_Changed">
<SymbolIcon Symbol="TouchPointer" />
</InkToolbarCustomToggleButton>
</InkToolbar>
<TextBlock x:Name="deviceInfo" />
<Border
Width="480"
Height="280"
HorizontalAlignment="Left"
Background="White"
BorderBrush="{ThemeResource SystemControlForegroundChromeHighBrush}"
BorderThickness="1">
<InkCanvas x:Name="inkCanvas" AutomationProperties.Name="Drawing surface" />
</Border>
</StackPanel>
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Windows.UI.Core;
public sealed partial class MainPage : Page
{
public MainPage()
{
InitializeComponent();
// Pen and mouse input always draw ink. The custom toggle controls touch input.
inkCanvas.InkPresenter.InputDeviceTypes = CoreInputDeviceTypes.Pen | CoreInputDeviceTypes.Mouse;
ShowDevices();
}
private void TouchWritingToggle_Changed(object sender, RoutedEventArgs e)
{
if (touchWritingToggle.IsChecked == true)
{
inkCanvas.InkPresenter.InputDeviceTypes |= CoreInputDeviceTypes.Touch;
}
else
{
inkCanvas.InkPresenter.InputDeviceTypes &= ~CoreInputDeviceTypes.Touch;
}
ShowDevices();
}
private void ShowDevices()
{
deviceInfo.Text = $"InputDeviceTypes = {inkCanvas.InkPresenter.InputDeviceTypes}";
}
}
De wisselknop toont alleen een pictogram, dus geeft het voorbeeld deze een toegankelijke naam en knopinfo. In dit voorbeeld maakt de werkbalk ook de standaardknoppen en wordt de aangepaste wisselknop erna weergegeven.
De werkbalk ondersteunt andere aangepaste knoppen:
-
InkToolbarCustomToolButtonvoegt een eigen hulpprogramma toe. -
InkToolbarCustomPenButtonvoegt een pen met eigen tekenkenmerken toe.CustomPenStel de eigenschap ervan in op een instantie van een klasse die is afgeleid vanInkToolbarCustomPenen overschrijft deCreateInkDrawingAttributesCoremethode.
De werkbalk in code maken
U kunt ook het canvas en de werkbalk in code maken. In het volgende voorbeeld worden ze toegevoegd aan een Border met de naam inkHost, wordt de werkbalk verbonden met TargetInkPresenter en wordt het potlood geselecteerd wanneer de werkbalk wordt geladen.
<Border x:Name="inkHost" HorizontalAlignment="Left" />
using Microsoft.UI;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Automation;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
using Windows.UI.Core;
public sealed partial class MainPage : Page
{
public MainPage()
{
InitializeComponent();
CreateInkingUI();
}
private void CreateInkingUI()
{
InkCanvas canvas = new();
AutomationProperties.SetName(canvas, "Drawing surface");
canvas.InkPresenter.InputDeviceTypes =
CoreInputDeviceTypes.Pen | CoreInputDeviceTypes.Mouse | CoreInputDeviceTypes.Touch;
InkToolbar toolbar = new() { TargetInkPresenter = canvas.InkPresenter };
AutomationProperties.SetName(toolbar, "Drawing tools");
// The toolbar creates its built-in buttons when it loads.
toolbar.Loaded += (sender, args) => toolbar.ActiveTool = toolbar.GetToolButton(InkToolbarTool.Pencil);
Border canvasFrame = new()
{
Width = 480,
Height = 280,
Background = new SolidColorBrush(Colors.White),
BorderBrush = new SolidColorBrush(Colors.DarkGray),
BorderThickness = new Thickness(1),
Child = canvas,
};
StackPanel layout = new() { Spacing = 8 };
layout.Children.Add(toolbar);
layout.Children.Add(canvasFrame);
inkHost.Child = layout;
}
}
Bekende beperkingen
- De inktbesturingselementen zijn alleen beschikbaar in experimentele releases van de Windows App SDK. Ze zijn niet beschikbaar in het stabiele kanaal.
- De inkt-API's bevatten geen handschrift- of vormherkenning.
- De muisinvoer tekent pas inkt totdat u
CoreInputDeviceTypes.MouseaanInputDeviceTypestoevoegt.
De volgende problemen zijn gerapporteerd met Windows App SDK experimenteel 2.4.1. In de releaseopmerkingen voor 2.5.4-experimental worden ze niet vermeld als opgelost:
- De liniaal- en gradenboogstencils werken niet.
-
RenderTargetBitmaplegt geen inkt vast. Als u een afbeelding van de inkt wilt maken, slaat u deze op in deGifWithEmbeddedIsfindeling. - Als u in XAML de eigenschap
Palettevan een penknop instelt, wordt er een XAML-parseringsfout veroorzaakt. StelPalettein plaats daarvan in de code in, zoals wordt weergegeven in De kleuren en breedte van een pen aanpassen. - Flyouts van knoppen kunnen leeg lijken en het wijzigen van
ButtonFlyoutPlacementwijzigt mogelijk niet waar ze worden geopend.
Wijzigingen in 2.4.1-experimenteel
Als u de inkt-API's in Windows App SDK 2.4.1-experimenteel hebt gebruikt, werkt u de code voor deze wijzigingen bij in 2.5.4-experimenteel:
| API in 2.4.1-experimenteel | Wijziging in 2.5.4-experimenteel |
|---|---|
InkToolbar.TargetInkPresenter (type Object) |
Het type van de eigenschap is InkPresenter. |
methoden voor InkPresenter.GetHighContrastAdjustment en InkPresenter.SetHighContrastAdjustment |
Vervangen door de InkPresenter.HighContrastAdjustment eigenschap. |
methoden voor InkStrokeInput.GetInkPresenter en InkUnprocessedInput.GetInkPresenter |
Vervangen door een InkPresenter eigenschap in elke klasse. |
InkToolbarEraserButton.SelectedEraser, IsStrokeEraserVisible en InkToolbar.EraserFlyoutItemClicked eigenschappen; InkToolbarEraserKind gebeurtenis; InkToolbarEraserFlyoutItemKind, InkToolbarEraserFlyoutItemClickedEventArgs en ArePrecisionErasersVisible typen |
Verwijderd. |
| Niet beschikbaar |
InkPresenter.ActivateCustomDrying methode en InkSynchronizer klasse toegevoegd. |
Toegankelijkheid en hoog contrast
Inkt is visuele inhoud, dus plan hoe alle gebruikers uw inktfuncties kunnen gebruiken:
- Geef elk canvas en elke werkbalk een toegankelijke naam met
AutomationProperties.Name, zoals de voorbeelden in dit artikel doen. Geef aangepaste knoppen die alleen een pictogram weergeven een naam en knopinfo. -
InkCanvasAutomationPeerstelt het canvas beschikbaar aan UI Automation, maar beschrijft de pennenstreken niet. Als de inkt betekenis heeft, zoals een handtekening of een gelabeld diagram, geef een alternatieve tekst op. - Tekenen met inkt vereist aanwijzerinvoer. Gebruik inkt niet als de enige manier om een taak te voltooien. Laat gebruikers bijvoorbeeld hun naam typen als alternatief voor het ondertekenen ervan.
- De automation peers voor de ingebouwde toolknoppen ondersteunen de SelectionItem- en ExpandCollapse-besturingspatronen. Test toetsenbordnavigatie en de fly-outs van de knoppen met de werkbalkconfiguratie die uw app gebruikt.
Wanneer een contrastthema actief is, kan de presentator inktkleuren vervangen door systeemkleuren. Als u dit gedrag wilt kiezen, stelt u de HighContrastAdjustment eigenschap in op een InkHighContrastAdjustment waarde uit de Microsoft.UI.Xaml.Controls naamruimte. In de Windows Runtime documentatie voor de opsomming met dezelfde naam worden de waarden op deze manier beschreven:
| Value | Inktkleur in een contrastthema |
|---|---|
UseSystemColorsWhenNecessary |
De eigen kleur van de inkt als deze voldoende contrasteert met de achtergrond. Anders een systeemkleur. |
UseSystemColors |
Een systeemkleur. Markeerinkt maakt gebruik van de systeemmarkeringskleur. |
UseOriginalColors |
De kleur van de inkt. |
inkCanvas.InkPresenter.HighContrastAdjustment = InkHighContrastAdjustment.UseSystemColorsWhenNecessary;
Om ze kort te houden, stellen de voorbeelden in dit artikel rechtstreeks een witte achtergrond in. Definieer in uw app de achtergrond van het canvas in themawoordenboeken, zodat deze het actieve thema volgt, zoals beschreven in contrastthema's. Test vervolgens uw app met elk contrastthema en controleer of de voorgrond, de achtergrond en de rand onderscheidbaar blijven.
Zie Basisinformatie over toegankelijkheid beschikbaar maken en Toegankelijkheid via het toetsenbord voor meer informatie.
Zie ook
- WinUI 3 Gallery InkCanvas-voorbeeldbroncode
- Windows App SDK 2.5.4-experimentele releasenotities
- Microsoft.UI.Xaml.Controls-naamruimte
- Windows.UI.Input.Inking-naamruimte
- Pen haptische feedback in Windows apps
- Peninteractie en Windows Ink (UWP)
- Invoerbesturingselementen voor inkt (UWP)
- Wat wordt ondersteund bij het migreren van UWP naar WinUI 3
Windows developer