Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Important
InkCanvas, InkToolbar és InkPresenter kísérleti API-k. A szabadkézírás támogatása a Windows App SDK 2.4.1-experimental verzióban lett hozzáadva. Ez a cikk a Windows App SDK 2.5.4-experimental verziót ismerteti, amely megváltoztatta, hogyan csatlakoztat egy InkToolbar-t. Ezek az API-k nem érhetők el a stabil csatornán. Előfordulhat, hogy egy későbbi kiadásban megváltoznak, vagy el lesznek távolítva. Ne használd őket produkciós alkalmazásokban.
A kísérleti InkCanvas vezérlővel tollal, egérrel vagy érintéssel rajzolhat szabadkézi elemeket. Adjon hozzá egy InkToolbar eszközt, amely golyóstollat, ceruzát, kiemelőt és radírt biztosít a felhasználóknak, szín- és méretbeállításokkal. Minden vásznon van egy InkPresenter, amely a szabadkézi bemenetet gyűjti és rendereli. Az előadó InkStrokeContainer eleme tárolja a tollvonásokat, így a kódban mentheti, betöltheti, másolhatja és létrehozhatja a szabadkézi elemeket.
A vezérlők kipróbálásához telepítse a Windows App SDK 2.5.4-kísérleti csomagot és a megfelelő futtatókörnyezetet. A letöltési hivatkozásokkal és a beállítással kapcsolatos információkért tekintse meg a legújabb Windows App SDK letöltéseket.
Ez a megfelelő vezérlő?
Használjon rajzvásznat, amikor a felhasználóknak a következőkre van szükségük:
- Készítsen kézzel írt jegyzeteket, vagy annotálja a tartalmat.
- Vázlatot készíthetnek, diagramokat rajzolhatnak vagy aláírhatják a nevüket.
- Szabadkézi tartalmakat hozhat létre, amelyeket az alkalmazás ment, és amelyeket később szerkeszthet.
A kísérleti tintakezelési API-k nem tartalmazzák a kézírást és az alakzatfelismerést. Szöveg gyűjtéséhez használjon szövegdobozt.
Ha éles alkalmazásban digitális tintakezelésre van szüksége, a ismert vezérlőhiányosságok között talál információt ezeknek a vezérlőknek a stabil csatornában lévő állapotáról, valamint az alternatívákról.
A tintázási modell ismertetése
A digitálistinta-API-k együttműködnek:
| API | Role |
|---|---|
InkCanvas |
A szabadkézi elemeket megjelenítő XAML-elem, amely szabadkézi bemenetet fogad. A InkPresenter tulajdonság visszaadja a canvas prezentálóját. |
InkPresenter |
Gyűjti a szabadkézi bemenetet, rendereli a vonásokat, és tárolja a bemeneti beállításokat és az alapértelmezett rajzattribútumokat. Nem hozhat létre ilyet saját maga. Szerezze be innen: InkCanvas.InkPresenter |
InkStrokeContainer |
Vonásokat tárol. Ezzel mentheti, betöltheti, kijelölheti, másolhatja és beillesztheti a tintát. Szerezze be innen: InkPresenter.StrokeContainer. |
InkToolbar |
Választható eszköztár, amellyel a felhasználók tollat, ceruzát, kiemelőt vagy radírt választhatnak, és módosíthatják a tinta színét és méretét. |
InkCanvas nem rendelkezik Background tulajdonsággal. Ha hátteret és szegélyt szeretne adni a rajzterületnek, helyezze a canvast egy tárolóba, például egy Border elembe, és állítsa be a méretet a tárolón. A tinta alapértelmezett színe fekete, ezért a cikkben szereplő példák fehér hátteret használnak.
Ezen típusok közül többnek ugyanaz a neve, mint a Windows-futtatókörnyezet Windows.UI.Input.Inking névtérben található típusoknak, például InkPresenter, InkStrokeContainer és InkHighContrastAdjustment. A szabadkézési vezérlők a Microsoft.UI.Xaml.Controls verziókat használják. A vonások és a rajzolási attribútumok továbbra is Windows-futtatókörnyezet típusokat használnak, például InkStroke, InkDrawingAttributes és InkStrokeBuilder. Ha mindkét névteret importálja, és nem egyértelmű nevet használ, a C# fordító CS0104 hibát jelez.
Az ebben a cikkben szereplő példák importálják a(z) Microsoft.UI.Xaml.Controls elemet, és alias-irányelveket használnak a szükséges Windows.UI.Input.Inking típusokhoz:
using Microsoft.UI.Xaml.Controls;
using InkDrawingAttributes = Windows.UI.Input.Inking.InkDrawingAttributes;
using InkStroke = Windows.UI.Input.Inking.InkStroke;
Mindkét névteret importálhatja, és teljesen minősített neveket is használhat a nem egyértelmű típusokhoz, ahogyan a WinUI 3 katalógusminta teszi.
InkPresenter emellett olyan alacsonyabb szintű API-kat is biztosít, amelyekre ez a cikk nem terjed ki:
-
StrokeInputeseményeket hoz létre, amikor egy vonás elindul, folytatódik, véget ér vagy megszakad. -
UnprocessedInputolyan beviteli mutatóeseményeket vált ki, amelyeket a prezentáló nem szabadkézi bevitelként dolgoz fel. -
InputConfigurationbeállítja, hogy a prezentáló feldolgozza-e a toll radírjából és az elsődleges oldalsó gombból érkező bemenetet. -
InputProcessingConfigurationBeállítja, hogy a bemenet rajzoljon-e szabadkézi elemeket, törölje-e a szabadkézi elemeket, vagy ne legyen feldolgozva, és hogy az előadó hogyan kezeli a jobb gombbal történő húzásos bevitelt. -
ActivateCustomDryingolyan alkalmazásokhoz ad vissza egyInkSynchronizerelemet, amelyek maguk renderelik a véglegesített tintát.
Állítsa be a projektjét
A rajzolási API-k kísérletinek vannak megjelölve. Ha egy C#-projektben használja őket, a C# fordító CS8305 figyelmeztetést ad, az XAML fordító pedig WMC1501 figyelmeztetést ad. Ha a projekt hibaként kezeli a figyelmeztetéseket, ezek a figyelmeztetések leálltatják a buildet.
Miután úgy dönt, hogy a kísérleti API-kat használja, letilthatja ezeket a figyelmeztetéseket. Adja hozzá a következő tulajdonságokat a C# projektfájlhoz (.csproj):
<PropertyGroup>
<NoWarn>$(NoWarn);CS8305</NoWarn>
<MSBuildWarningsAsMessages>$(MSBuildWarningsAsMessages);WMC1501</MSBuildWarningsAsMessages>
</PropertyGroup>
A cikkben szereplő példák a C#-ot használják. Minden teljes példa egy lap XAML-jét és a lap code-behind osztályát mutatja be, MainPage.
Rajzvászon létrehozása
![]()
A WinUI 3 Katalógus alkalmazás interaktív példákat tartalmaz a WinUI vezérlőire és funkcióira. Kérje le az alkalmazást a Microsoft Áruházból vagy keresse meg a forráskódot a GitHub webhelyen.
Az alábbi példa egy vásznat helyez egy fehér elembe Border. A mögöttes kód beállítja a bemeneti eszköztípusokat, hogy a felhasználók tollal, egérrel vagy érintéssel rajzolhassanak.
<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;
}
}
Hogy rövidek maradjanak, néhány későbbi példa nem ismétli meg ezt a kódot. Állítsa be a(z) InputDeviceTypes elemet minden olyan oldalon, ahol a felhasználók egérrel rajzolnak.
Szabadkéz eszköztár csatlakoztassa
Helyezzen el egy InkToolbar elemet a vászon közelében, és állítsa be a(z) TargetInkCanvas tulajdonságát a kettő összekapcsolásához:
<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>
A Windows App SDK 2.5.4-kísérleti verziótól kezdve közvetlenül csatlakoztathat egy eszköztárat egy InkPresenter elemhez a TargetInkPresenter tulajdonság beállításával. Állítsa be kódban:
inkToolbar.TargetInkPresenter = inkCanvas.InkPresenter;
Az XAML-ben is beállíthatja: TargetInkPresenter="{x:Bind inkCanvas.InkPresenter}". A két céltulajdonság közül csak az egyiket állítsa be.
Az eszköztár alapértelmezés szerint a golyóstoll, a ceruza, a kiemelő, a radír és a rajzsablon (vonalzó) gombjait jeleníti meg. A megjelenő gombok módosításához lásd: A rajzeszköztár testreszabása.
Bemeneti eszközök kiválasztása
A InputDeviceTypes tulajdonság a Windows.UI.Core névtér CoreInputDeviceTypes jelzőfelsorolását használja. Az egérbevitel alapértelmezés szerint nem rajzol tintát. Az értékek kombinálásával kiválaszthatja, hogy mely eszközök használjanak szabadkézi bevitelt:
// 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);
Ha le szeretné állítani a tinta gyűjtését minden eszközről, például egy olyan rajz megjelenítéséhez, amelyet a felhasználók nem tudnak módosítani, állítsa a IsInputEnabled következőre: false
inkCanvas.InkPresenter.IsInputEnabled = false;
Ha azt szeretné, hogy a felhasználók be- vagy kikapcsolhassák a beviteli eszközt az eszköztárról, olvassa el az Egyéni váltógomb hozzáadása című témakört.
Rajzattribútumok beállítása
A rajzattribútumok, például a szín, a méret és a tollhegy alakzata vezérlik a vonások megjelenését. A Windows-futtatókörnyezet InkDrawingAttributes osztályt használják. Az új ecsetvonások attribútumainak módosításához hívja meg a(z) CopyDefaultDrawingAttributes elemet, módosítsa a másolatot, és adja át a(z) UpdateDefaultDrawingAttributes elemnek:
InkDrawingAttributes attributes = inkCanvas.InkPresenter.CopyDefaultDrawingAttributes();
attributes.Color = Colors.DarkBlue;
attributes.Size = new Size(4, 4);
inkCanvas.InkPresenter.UpdateDefaultDrawingAttributes(attributes);
Colors a Microsoft.UI névtérben van, és Size a Windows.Foundation névtérben van. Az új attribútumok a felhasználók által a hívás után rajzolt vonásokra vonatkoznak. A meglévő vonalak megtartják az attribútumaikat.
Amikor csatlakoztat egy InkToolbareszközt, az aktív eszköz és annak szín- és méretbeállításai határozzák meg a rajzattribútumokat. Az aktuális attribútumok olvasásához használja az eszköztár InkDrawingAttributes tulajdonságát.
Toll-előbeállítások létrehozása
Ha nem használ eszköztárat, saját toll-előbeállításokat is kínálhat. Az alábbi példa golyóstoll-, ceruza-, kiemelő- vagy kalligráfiai attribútumokat alkalmaz, amikor a felhasználó kiválaszt egy előre beállított értéket, vagy módosítja a méretet.
<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.CreateForPencila ceruzavonások attribútumait adja vissza. AKindtulajdonság írásvédett, ezért ezzel a módszerrel ceruzaattribútumokat hozhat létre. -
DrawAsHighlightera körvonalat kiemelő átfedésként jeleníti meg. -
PenTipbeállítja a tollhegy alakját, ésPenTipTransformelforgatja vagy skálázza azt. Az elforgatott négyszögletes csúcs kalligráfia stílusú vonásokat eredményez.
Reagálás a tintaváltozásokra
A megjelenítő a StrokesCollected elemet jelzi, miután a felhasználó tollvonásokat rajzol, és a StrokesErased elemet, miután a felhasználó törli őket. Az egyes események argumentumainak Strokes tulajdonsága tartalmazza az érintett tollvonásokat. Az alábbi kód naprakészen tartja a stroke-számot egy TextBlock nevű strokeCountText elemben:
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";
}
Ezek az események akkor fordulnak elő, amikor a felhasználók tintát rajzolnak vagy törölnek. Ha például a Clear, LoadAsync vagy AddStroke használatával módosítja a vonásokat a kódban, a hívás után frissítse a felhasználói felületet.
Tinta mentése és betöltése
InkStrokeContainer menti a tintát szabadkézi szerializált formátumban (ISF). Az adatok tárolási módjának kiválasztásához adjon át egy InkPersistenceFormat értéket a következőnek SaveAsync:
| Format | Output |
|---|---|
GifWithEmbeddedIsf |
A szabadkézadatokat tartalmazó GIF-kép. A képmegjelenítők megjeleníthetik a fájlt, és az alkalmazás újra betöltheti a digitális tintát szerkesztés céljából. |
Isf |
Csak tintaadatok, kép nélkül. Ez a legtömörebb formátum. |
Adja hozzá a következő metódusokat egy InkCanvas nevű inkCanvas elemet tartalmazó lap mögötti kódhoz.
SaveInkAsync Egy fájlba írja a tintát, és LoadInkAsync lecseréli a vászonon lévő tintát a fájlból származó tintára.
LoadAsync Eltávolítja a meglévő vonásokat, mielőtt hozzáadja a betöltött vonásokat, így nem kell először hívnia a(z) Clear függvényt.
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 és AsInputStream konvertálják a .NET streameket a SaveAsync és LoadAsync által használt Windows-futtatókörnyezet streamtípusokra. Ezen Windows-futtatókörnyezet-metódusok awaiteléséhez a fájlhoz szükséges a using System; irányelv. Nélküle a fordító cs4036-os hibát jelez.
Ha lehetővé szeretné tenni, hogy a felhasználók kiválasszanak egy fájlt, használja a Windows App SDK fájlválasztókat, amelyek a kijelölt fájl elérési útját adják vissza. További információért lásd: Fájl mentése Windows App SDK-választóval és Fájlok és mappák megnyitása Windows App SDK-választókkal.
Ha meg szeretné őrizni a tintát a memóriában, például ha később szeretné visszaállítani ugyanabban a munkamenetben, mentse azt egy InMemoryRandomAccessStream fájlba. Adja át az adatfolyam GetOutputStreamAt(0) eredményét SaveAsync számára, és adja át annak GetInputStreamAt(0) eredményét LoadAsync számára. A WinUI 3 katalógusminta ezt a megközelítést használja.
Tinta másolása és beillesztése
InkStrokeContainer képes vonásokat a vágólapra másolni, és onnan szabadkézi elemeket beilleszteni.
CopySelectedToClipboard csak a kijelölt vonásokat másolja, ezért az alábbi példa a bal oldali vásznon lévő összes vonást kijelöli, mielőtt azokat átmásolja.
CanPasteFromClipboard ellenőrzi, hogy a vágólap tartalmaz-e tintát.
PasteFromClipboard Hozzáadja a tintát az átadott pozícióban, és visszaadja a módosított terület határoló téglalapját.
<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.";
}
}
Egyes vonalak használatához állítsa be minden kívánt vonal Selected tulajdonságát, vagy hívja meg a(z) SelectWithPolyLine vagy SelectWithLine elemet. A kijelölt vonások törléséhez vagy áthelyezéséhez hívja meg a DeleteSelected vagy MoveSelected parancsot.
Körvonalak létrehozása a kódban
A Windows-futtatókörnyezet InkStrokeBuilder osztály használatával vonásokat hozhat létre pontokból, és a(z) AddStroke segítségével adhatja őket a vászonhoz. Az alábbi példa egy csillagot és egy aláírási sort ad hozzá.
<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);
}
}
-
CreateStrokeFromInkPointsvonást hoz létreInkPointértékekből. Minden pont a vásznon lévő pozícióból és egy nyomásértékből áll. - A Windows-futtatókörnyezet dokumentációja a tintabemutatóhoz hozzáadott tollvonásokhoz a
CreateStrokehelyett aCreateStrokeFromInkPointshasználatát ajánlja. - Ha a(z)
FitToCurvefalseértékre van állítva, akkor a vonás egyenes szegmenseket használ a pontok között a görbék helyett.
Egy tollvonás csak egy tárolóhoz tartozhat. Az ecsetvonások másik vászonra másolásához adja hozzá az ecsetvonások klónjait:
private void CopyStrokesTo(InkCanvas target)
{
foreach (InkStroke stroke in inkCanvas.InkPresenter.StrokeContainer.GetStrokes())
{
target.InkPresenter.StrokeContainer.AddStroke(stroke.Clone());
}
}
A tintaeszköztár testreszabása
A kezdeti vezérlők kiválasztása
A InitialControls tulajdonság határozza meg, hogy az eszköztár mely beépített gombokat hozza létre:
| Érték | Beépített gombok |
|---|---|
All (alapértelmezett) |
Golyóstoll, ceruza, kiemelő, radír és sablon (vonalzó) |
PensOnly |
Golyóstoll, ceruza és kiemelő |
AllExceptPens |
Radír és rajzsablon (vonalzó) |
None |
None. Deklarálja az eszköztár gyermekeiként használni kívánt gombokat. |
Az alábbi példa ugyanazt a négy gombot deklarálja, mint a WinUI 3 katalógusmintája, mindegyiknek egy akadálymentesítési nevet ad, és az eszköztár betöltésekor kiválasztja a golyóstollat:
<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;
}
};
}
}
Ha egy parancsot szeretne megjeleníteni, amely az összes tintát törli, állítsa a radírgomb IsClearAllVisible tulajdonságát true értékre. Az eszköztár akkor kiváltja az EraseAllClicked eseményt, amikor a felhasználó kiválasztja a parancsot.
Toll színeinek és vastagságának testreszabása
Minden tollgombhoz tartozik egy Palette ecsetválaszték és ecsetvonásvastagság-beállítások. Állítsa be a(z) Palette elemet a kódban. További információ: Ismert korlátozások. Az alábbi példa egy golyóstoll palettáját négy márkaszínre cseréli, korlátozza a vonalvastagságot, és megjeleníti az aktív toll attribútumait.
<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 kiválaszt egy színt innen: Palette.
SelectedStrokeWidth, MinStrokeWidth és MaxStrokeWidth beállítják az aktuális körvonalszélességet és a felhasználók által választható tartományt. Az eszköztár kiváltja a(z) InkDrawingAttributesChanged eseményt, amikor az aktív eszköz attribútumai megváltoznak.
Válassza ki az aktív eszközt
Válassza ki az eszközt a ActiveTool segítségével, és a ActiveToolChanged kezelje azt, amikor a felhasználó kiválaszt egy másikat.
GetToolButton Egy olyan beépített eszközgombot ad vissza, amilyet megad. Előfordulhat, hogy a beépített gombok nem léteznek, amíg be nem töltődik az eszköztár, ezért válasszon egy kezdőeszközt az eszköztár Loaded eseménykezelőjében.
<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}";
}
}
Tájolás módosítása
Ha függőlegesen szeretné megjeleníteni az eszköztárat, például a vászon mellett, állítsa a(z) Orientation értékét erre: 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>
A ButtonFlyoutPlacement tulajdonság azt határozza meg, hogy a gomb úszó paneljei az eszköztárhoz képest hol nyílnak meg. Az alapértelmezett érték, Auto, lehetővé teszi, hogy az eszköztár válassza ki a pozíciót.
Egyéni kapcsológomb hozzáadása
Használjon egy InkToolbarCustomToggleButton elemet egy olyan beállítás hozzáadásához, amelyet a felhasználók be- és kikapcsolnak az eszköztárról. Az alábbi példa egy kapcsolót ad hozzá, amely szabályozza az érintéses bemenetet. A toll- és egérbemenet mindig tintát rajzol.
<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}";
}
}
A kapcsoló csak egy ikont jelenít meg, így a példa hozzáférhető nevet és eszköztippet ad neki. Ebben a példában az eszköztár létrehozza az alapértelmezett gombokat is, és az egyéni kapcsoló azok után jelenik meg.
Az eszköztár más egyéni gombokat is támogat:
-
InkToolbarCustomToolButtonsaját eszközt ad hozzá. -
InkToolbarCustomPenButtonHozzáad egy tollat, amely saját rajzattribútumokat hoz létre. Állítsa a(z)CustomPentulajdonságot egy olyan osztálypéldányra, amely a(z)InkToolbarCustomPenosztályból származik, és felülírja a(z)CreateInkDrawingAttributesCoremetódust.
Az eszköztár létrehozása kódban
A rajzfelületet és az eszköztárat kódban is létrehozhatja. Az alábbi példa hozzáadja őket egy inkHost nevű Border-hoz, összekapcsolja az eszköztárat a TargetInkPresenter elemmel, és kiválasztja a ceruzát, amikor az eszköztár betöltődik.
<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;
}
}
Ismert korlátozások
- A szabadkézvezérlők csak a Windows App SDK kísérleti kiadásaiban érhetők el. Ezek nem érhetők el a stabil csatornán.
- Az inkezelési API-k nem tartalmazzák a kézírás- vagy alakzatfelismerést.
- Az egér bemenete nem rajzol szabadkézi elemeket, amíg hozzá nem adja a(z)
CoreInputDeviceTypes.Mouseelemet a(z)InputDeviceTypeselemhez.
A következő problémákat jelentették a 2.4.1-kísérleti Windows App SDK-val kapcsolatban. A 2.5.4-es kísérleti kiadási megjegyzések nem javítottként sorolják fel őket:
- A vonalzó és a szögmérő sablonok nem működnek.
-
RenderTargetBitmapnem rögzíti a tintát. A tinta képének létrehozásához mentseGifWithEmbeddedIsfformátumban. - A tollgomb
Palettetulajdonságának beállítása az XAML-ben XAML-elemzési hibát okoz. Ehelyett állítsa be a(z)Paletteelemet a kódban, ahogyan az a a toll színeinek és szélességeinek testreszabása című témakörben látható. - A gomb úszó ablakai üresen jelenhetnek meg, és előfordulhat, hogy a
ButtonFlyoutPlacementmódosítása nem változtatja meg a megnyitás helyét.
Változások a 2.4.1-es kísérleti verziótól
Ha a Windows App SDK 2.4.1-kísérleti verziójában használta a szabadkézési API-kat, frissítse a kódját a 2.5.4-kísérleti verzió ezen változásaihoz:
| API a 2.4.1-experimental verzióban | Változás a 2.5.4-kísérletiben |
|---|---|
InkToolbar.TargetInkPresenter (típus: Object) |
A tulajdonság típusa: InkPresenter. |
InkPresenter.GetHighContrastAdjustment és InkPresenter.SetHighContrastAdjustment metódusok |
A(z) InkPresenter.HighContrastAdjustment tulajdonság váltja fel. |
InkStrokeInput.GetInkPresenter és InkUnprocessedInput.GetInkPresenter metódusok |
Az egyes osztályok egy-egy InkPresenter tulajdonsága helyettesíti. |
InkToolbarEraserButton.SelectedEraser, IsStrokeEraserVisible, és ArePrecisionErasersVisible tulajdonságok; InkToolbar.EraserFlyoutItemClicked esemény; InkToolbarEraserKind, InkToolbarEraserFlyoutItemKindés InkToolbarEraserFlyoutItemClickedEventArgs típusok |
Eltávolított. |
| Nem elérhető |
InkPresenter.ActivateCustomDrying metódus és InkSynchronizer osztály hozzáadva. |
Akadálymentesség és magas kontraszt
A szabadkéz vizuális tartalom, ezért tervezze meg, hogy minden felhasználó hogyan használhatja a szabadkézési funkciókat:
- Adjon minden vászonnak és eszköztárnak egy akadálymentes nevet
AutomationProperties.Name, ahogyan a cikkben szereplő példák is. Adjon nevet és elemleírást az olyan egyéni gomboknak, amelyek csak egy ikont jelenítenek meg. -
InkCanvasAutomationPeerelérhetővé teszi a vászon/canvast az UI-automatizálás számára, de nem írja le a vonásokat. Ha a tinta jelentéssel rendelkezik, például aláírást vagy címkézett diagramot, adjon meg egy szöveges alternatívát. - A szabadkézi rajzoláshoz mutatóbemenet szükséges. Ne csak tintával lehessen elvégezni egy feladatot. Például a felhasználók az aláírás alternatívájaként beírhatják a nevüket.
- A beépített eszközgombok automatizálási társobjektumai támogatják a SelectionItem és az ExpandCollapse vezérlőmintákat. Tesztelje a billentyűzet navigációját és a gombok felugró menüit az alkalmazás által használt eszköztár-konfigurációval.
Ha egy kontraszttéma aktív, az előadó lecserélheti a tinta színeit rendszerszínekre. Ennek a viselkedésnek a kiválasztásához állítsa a HighContrastAdjustment tulajdonságot a InkHighContrastAdjustment névtérből származó Microsoft.UI.Xaml.Controls értékre. Az azonos nevű enumerálás Windows-futtatókörnyezet dokumentációja így írja le az értékeket:
| Érték | Tintaszín egy kontrasztos témában |
|---|---|
UseSystemColorsWhenNecessary |
A tinta saját színe, ha eléggé kontrasztban áll a háttérrel. Ellenkező esetben rendszerszín. |
UseSystemColors |
A rendszer színe. A kiemelő tintája a rendszerkiemelő színét használja. |
UseOriginalColors |
A tinta saját színe. |
inkCanvas.InkPresenter.HighContrastAdjustment = InkHighContrastAdjustment.UseSystemColorsWhenNecessary;
A rövidség kedvéért a cikkben szereplő példák közvetlenül fehér háttérszínt állítanak be. Az alkalmazásban definiálja a canvas hátterét a témaszótárakban, hogy az az aktív témát kövesse a Kontraszttémák című témakörben leírtak szerint. Ezután tesztelje az alkalmazást minden kontraszttémával, és ellenőrizze, hogy az előtér, a háttér és a szegély megkülönböztethető marad-e.
További információ: Alapvető akadálymentességi információk közzététele és a billentyűzetes akadálymentesítés.
Lásd még
- WinUI 3 Gallery InkCanvas minta forráskód
- A Windows App SDK 2.5.4 kísérleti verziójának kiadási megjegyzései
- Microsoft.UI.Xaml.Controls névtér
- Windows.UI.Input.Inking névtér
- Tollal adott haptikus visszajelzés a Windows-alkalmazásokban
- Toll-interakciók és Windows Ink (UWP)
- Tintakezelő vezérlők (UWP)
- Mi támogatott az UWP-ről WinUI 3-ra való migráláskor?
Windows developer