Implement first-class inking support (InkCanvas + InkToolBar)#11016
Open
Nitin-100 wants to merge 2 commits intomicrosoft:mainfrom
Open
Implement first-class inking support (InkCanvas + InkToolBar)#11016Nitin-100 wants to merge 2 commits intomicrosoft:mainfrom
Nitin-100 wants to merge 2 commits intomicrosoft:mainfrom
Conversation
- Expand InkCanvas API: Mode (Draw/Erase/Select), AllowedInputTypes, DefaultDrawingAttributes, StrokeContainer, SaveAsync/LoadAsync, ClearStrokes, StrokeCollected/StrokesErased events - Add InkCanvasMode enum, InkInputType flags enum - Add InkCanvasStrokeCollectedEventArgs, InkCanvasStrokesErasedEventArgs - Implement InkToolBar: replace E_NOTIMPL skeleton with full tool management, InkPresenter integration, default tool button creation - Enable FeatureInkToolBarEnabled in FeatureAreas.props - Update vcxitems, generated properties, and XAML metadata
- InkCanvas APITests (17 tests): property defaults, Mode/AllowedInputTypes/ IsEnabled/DefaultDrawingAttributes cycling, DependencyProperty access, StrokeContainer/ClearStrokes safety, event subscription, XAML integration, multiple instance independence - InkToolBar APITests (24 tests): constructor, InitialControls/Orientation/ ButtonFlyoutPlacement/IsRulerButtonChecked/IsStencilButtonChecked properties, TargetInkCanvas/TargetInkPresenter binding, ActiveTool/Children access, GetToolButton/GetToggleButton/GetMenuButton, all DependencyProperties exist, event subscriptions, BallpointPenButton/PencilButton/HighlighterButton/ CustomToolButton/CustomToggleButton/StencilButton/FlyoutItem/ PenConfigurationControl construction, XAML visual tree tests - InkCanvas TestUI: interactive page with mode selector, input type checkboxes, save/load/clear buttons, stroke count display, event status - InkToolBar TestUI: interactive page with InitialControls/Orientation/ FlyoutPlacement selectors, ruler/stencil toggles, linked InkCanvas, active tool and event status display - InkCanvas InteractionTests (6 tests): visual tree presence, mode switching, input type configuration, clear strokes, save/load, stroke count display - InkToolBar InteractionTests (7 tests): visual tree presence, InitialControls selection, orientation switching, flyout placement, ruler/stencil toggle, active tool display - Registered all test projects in MUXControlsTestApp.csproj and MUXControls.Test.csproj with feature flag conditions
Contributor
|
This probably isn't going to land in WinUI directly due to breaking API/etc. A better approach would be to submit this as a control to the Windows Community Toolkit, where it can get community feedback, be iterated on, and potentially/eventually get promoted into the core library if needed. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implement First-Class Inking Support (InkCanvas + InkToolBar)
Summary
This PR implements first-class inking support in WinUI 3 by expanding the
InkCanvasAPI surface and replacing theInkToolBarE_NOTIMPL skeleton with a full working implementation. The changes follow the existing WinUI C++/WinRT patterns and integrate with theInkPresenterdesktop infrastructure already in place.Changes
InkCanvas API Expansion
src/controls/dev/InkCanvas/InkCanvas.idlInkCanvasModeenum (Draw/Erase/Select),InkInputTypeflags enum (Pen/Touch/Mouse),InkCanvasStrokeCollectedEventArgs,InkCanvasStrokesErasedEventArgsruntime classes. ExtendedInkCanvaswith Mode, AllowedInputTypes, DefaultDrawingAttributes properties, StrokeContainer accessor, SaveAsync/LoadAsync persistence methods, ClearStrokes, and StrokeCollected/StrokesErased events.src/controls/dev/InkCanvas/InkCanvas.hOnModePropertyChanged,OnAllowedInputTypesPropertyChanged,OnDefaultDrawingAttributesPropertyChanged), publicStrokeContainer(),SaveAsync(),LoadAsync(),ClearStrokes()methods, and private helpers (UpdateInkPresenterMode,UpdateInkPresenterInputTypes,SetupStrokeEvents).src/controls/dev/InkCanvas/InkCanvas.cppInkInputProcessingMode, input type filtering maps toCoreInputDeviceTypes, persistence usesInkStrokeContainer.SaveAsync/LoadAsyncqueued on the ink thread viatask_completion_event, stroke events bridgeInkPresenter.StrokesCollected/StrokesErasedto the WinUI event surface.src/controls/dev/InkCanvas/InkCanvasStrokeCollectedEventArgs.hInkStroke.src/controls/dev/InkCanvas/InkCanvasStrokesErasedEventArgs.hIVectorView<InkStroke>.src/controls/dev/InkCanvas/InkCanvas.vcxitemsInkToolBar Implementation
src/controls/dev/InkToolBar/InkToolBar.hE_NOTIMPLone-liners with proper method declarations. Added private state: tool button vectors, orientation, flyout placement, initial controls config, default-tools-created flag. AddedOnApplyTemplate,CreateDefaultToolButtons,UpdateInkPresenterFromActiveTool,OnActiveToolChanged,OnTargetInkCanvasChanged,GetInkPresenterhelpers.src/controls/dev/InkToolBar/InkToolBar.cppInitialControls, manages active tool state, synchronizes inking/erasing mode on the linkedInkCanvas'sInkPresenter, resolves presenter from eitherTargetInkCanvasor explicitTargetInkPresenter.src/controls/dev/InkToolBar/InkToolBar.vcxitemsInkToolBar.cppand all existing subclass headers (BallpointPenButton, PencilButton, HighlighterButton, EraserButton, StencilButton, CustomPen, toggles, menus, flyout items, automation peers, trace).Build & Feature Flags
src/controls/FeatureAreas.propsFeatureInkToolBarEnabled:false→truesrc/controls/dev/Generated/InkCanvas.properties.hAllowedInputTypes,DefaultDrawingAttributes,Modedependency properties,StrokeCollected/StrokesErasedevent sources.src/controls/dev/Generated/InkCanvas.properties.cppsrc/controls/dev/Generated/InkToolBarMenuButton.properties.h/.cppMenuKinddependency property (provided by base class, was duplicated).src/controls/dev/dll/XamlMetadataProviderGenerated.hInkCanvasproperties/methods andInkToolBartypes, enabling XAML tooling and runtime reflection.New API Surface
enum InkCanvasMode { Draw, Erase, Select }; [flags] enum InkInputType { None, Pen, Touch, Mouse }; runtimeclass InkCanvasStrokeCollectedEventArgs { Windows.UI.Input.Inking.InkStroke Stroke { get; }; }; runtimeclass InkCanvasStrokesErasedEventArgs { IVectorView<InkStroke> Strokes { get; }; }; unsealed runtimeclass InkCanvas : FrameworkElement { // Existing Boolean IsEnabled { get; set; }; IAsyncAction QueueInkPresenterWorkItem(DoInkPresenterWork workItem); // New InkCanvasMode Mode { get; set; }; // Default: Draw InkInputType AllowedInputTypes { get; set; }; // Default: Pen | Mouse InkDrawingAttributes DefaultDrawingAttributes { get; set; }; InkStrokeContainer StrokeContainer { get; }; // Read-only access IAsyncAction SaveAsync(IOutputStream stream); IAsyncAction LoadAsync(IInputStream stream); void ClearStrokes(); event TypedEventHandler<InkCanvas, InkCanvasStrokeCollectedEventArgs> StrokeCollected; event TypedEventHandler<InkCanvas, InkCanvasStrokesErasedEventArgs> StrokesErased; };Design Decisions
Ink thread safety: All
InkPresenterinteractions are queued viaQueueInkPresenterWorkItem/GenericInkCallback, following the existing pattern.SaveAsyncandLoadAsyncusetask_completion_eventto bridge async work across threads.Event bridging: Stroke events subscribe to
InkPresenter.StrokesCollected/StrokesErased(which fire on the ink thread) and re-raise through the generatedevent_sourceon the UI thread.InkToolBar integration:
InkToolBarresolves theInkPresenterviawinrt::get_self<InkCanvas>()->InkPresenter()whenTargetInkCanvasis set, or falls back toTargetInkPresenterfor advanced scenarios.Feature flag:
FeatureInkToolBarEnabledis flipped totrue. InkCanvas was already enabled.Testing
Full test infrastructure following the repo's standard 3-layer pattern (APITests, TestUI, InteractionTests) for both controls, registered in
MUXControlsTestApp.csprojandMUXControls.Test.csprojwith feature flag gating.InkCanvas Tests (23 tests)
APITests (
InkCanvas/APITests/InkCanvasTests.cs) — 17 unit tests:Modeproperty cycling (Draw → Erase → Select → Draw)AllowedInputTypesflags (Pen, Touch, Mouse, combined, None)IsEnabledtoggleDefaultDrawingAttributesset/get (color, size, pen tip)StrokeContaineraccessor safety (pre-load)ClearStrokessafety (pre-load)StrokeCollected/StrokesErasedevent subscriptionModeProperty,AllowedInputTypesProperty,DefaultDrawingAttributesProperty,IsEnabledProperty)TestUI (
InkCanvas/TestUI/InkCanvasPage.xaml/.cs):[TopLevelTestPage(Name = "InkCanvas")]StrokeContainerStrokeCollected/StrokesErasedevent handlersInteractionTests (
InkCanvas/InteractionTests/InkCanvasTests.cs) — 6 integration tests:InkToolBar Tests (31 tests)
APITests (
InkToolBar/APITests/InkToolBarTests.cs) — 24 unit tests:InitialControlsproperty (All/None/PensOnly/AllExceptPens)Childrencollection accessOrientationproperty (Horizontal/Vertical)ButtonFlyoutPlacementproperty (Auto/Top/Bottom/Left/Right)IsRulerButtonChecked/IsStencilButtonCheckedtoggleTargetInkCanvasbinding and clearingTargetInkPresenterbindingActiveTool/InkDrawingAttributesaccessGetToolButton/GetToggleButton/GetMenuButtonlookupActiveToolChanged/InkDrawingAttributesChanged/EraseAllClickedevent subscriptionInkToolBarBallpointPenButton,InkToolBarPencilButton,InkToolBarHighlighterButton,InkToolBarCustomToolButton,InkToolBarCustomToggleButton,InkToolBarStencilButton,InkToolBarFlyoutItem,InkToolBarPenConfigurationControlTestUI (
InkToolBar/TestUI/InkToolBarPage.xaml/.cs):[TopLevelTestPage(Name = "InkToolBar")]InkCanvasviaTargetInkCanvasbindingInteractionTests (
InkToolBar/InteractionTests/InkToolBarTests.cs) — 7 integration tests:Standalone Validation App
A separate WinUI 3 test application (
InkingTestApp) was built outside the repo to validate theWindows.UI.Input.Inkingdata model APIs:InkStrokeBuilder,InkStrokeContainer,InkDrawingAttributes, serialization round-trip, and attribute fidelityInMemoryRandomAccessStreamsave/load with visual verificationAll 16 tests pass. Not included in this PR.