A ProEssentials v11 WinUI 3 .NET 10 demonstration of two complementary
mouse-interaction techniques shown together in a single PegoWinUI
dual-Y-axis chart.
| Technique | API Surface | Best For |
|---|---|---|
| Tooltip — both Y values at cursor | ConvPixelToGraph + PeCustomTrackingDataText |
Reading interpolated values at any position, between data points |
| Status bar — named element under cursor | GetHotSpot + SearchSubsetPointIndex |
Identifying chart elements by name, driving click actions |
Both techniques run simultaneously from the same chart. Move the mouse to see them work together.
The chart-configuration code is identical to the WPF and WinForms versions of this example. The ProEssentials API does not change between interfaces; only the window plumbing differs.
The last subset is assigned to the right Y axis via RYAxisComparisonSubsets:
Pego1.PePlot.RYAxisComparisonSubsets = 1; // last 1 subset → right Y
Pego1.PePlot.Method = GraphPlottingMethod.PointsPlusSpline;
Pego1.PePlot.MethodII = GraphPlottingMethodII.Line; // right Y style
Pego1.PeString.YAxisLabel = "Units Sold";
Pego1.PeString.RYAxisLabel = "Market Share (%)";
Pego1.PeColor.RYAxis = GoldColor; // sync axis color to subset colorConvPixelToGraph converts mouse pixel coordinates to data-unit coordinates.
Called twice — once per Y axis — to read both scales at the cursor position:
private void Pego1_PeCustomTrackingDataText(object sender,
Gigasoft.ProEssentials.EventArg.CustomTrackingDataTextEventArgs e)
{
// WinUI returns WinRT geometry types here; WPF returned System.Windows.Point/Rect
Windows.Foundation.Point pt = Pego1.PeUserInterface.Cursor.LastMouseMove;
Windows.Foundation.Rect r = Pego1.PeFunction.GetRectGraph();
if (!r.Contains(pt)) return;
int nA = 0, nX = (int)pt.X, nY = (int)pt.Y;
double fX = 0, fLY = 0, fRY = 0;
// Left Y axis
Pego1.PeFunction.ConvPixelToGraph(ref nA, ref nX, ref nY, ref fX, ref fLY,
false, false, false);
// Right Y axis — reset coords then call again with rightAxis = true
nX = (int)pt.X; nY = (int)pt.Y; nA = 0;
Pego1.PeFunction.ConvPixelToGraph(ref nA, ref nX, ref nY, ref fX, ref fRY,
true, false, false);
e.TrackingText = $"Left Y ← {fLY:0.0} (units)\n{fRY:0.0} (%) → Right Y";
}Key points:
TrackingCustomDataText = trueactivates the evente.TrackingTextreplaces the default tooltip string- Works continuously between data points — values are interpolated
TrackingPromptTrigger == CursorMovemeans a keyboard arrow key moved the cursor to a snapped data point — readPeData.Ydirectly instead
GetHotSpot() returns the named chart element under the current mouse
position. The PointerMoved handler updates the status TextBlock:
private void Pego1_MouseMove(object sender, PointerRoutedEventArgs e)
{
Gigasoft.ProEssentials.Structs.HotSpotData ds = Pego1.PeFunction.GetHotSpot();
if (ds.Type == HotSpotType.DataPoint)
{
// ds.Data1 = subset index, ds.Data2 = point index
float val = Pego1.PeData.Y[ds.Data1, ds.Data2];
StatusText.Text = $"Data point · {Pego1.PeString.SubsetLabels[ds.Data1]}"
+ $" · {Pego1.PeString.PointLabels[ds.Data2]} · {val:0.0}";
}
else if (ds.Type == HotSpotType.Subset)
StatusText.Text = $"Series legend · {Pego1.PeString.SubsetLabels[ds.Data1]}";
else if (ds.Type == HotSpotType.Point)
StatusText.Text = $"Point label · {Pego1.PeString.PointLabels[ds.Data1]}";
else
{
// Not over a named element — find nearest data point
Windows.Foundation.Point pt = Pego1.PeUserInterface.Cursor.LastMouseMove;
Gigasoft.ProEssentials.Structs.Point nResult =
Pego1.PeFunction.SearchSubsetPointIndex((int)pt.X, (int)pt.Y);
if (nResult.X >= 0)
{
int s = Pego1.PeFunction.ClosestSubsetIndex;
int p = Pego1.PeFunction.ClosestPointIndex;
StatusText.Text = $"Nearest · {Pego1.PeString.SubsetLabels[s]}"
+ $" · {Pego1.PeString.PointLabels[p]}"
+ $" · {Pego1.PeData.Y[s, p]:0.0}";
}
}
}HotSpotData struct fields:
| Field | Meaning |
|---|---|
ds.Type |
HotSpotType enum — DataPoint, Subset, Point, None, ... |
ds.Data1 |
Subset index for DataPoint/Subset; point index for Point |
ds.Data2 |
Point index for DataPoint |
Enable hotspot hit testing:
Pego1.PeUserInterface.HotSpot.Data = true; // data points
Pego1.PeUserInterface.HotSpot.Subset = true; // series legends
Pego1.PeUserInterface.HotSpot.Point = true; // X-axis labels
Pego1.PeUserInterface.HotSpot.Size = HotSpotSize.Large;Wiring the pointer event in WinUI:
// WPF used MouseMove="Pego1_MouseMove" as a XAML attribute. In WinUI the chart
// control forwards pointer input to the native engine and marks the routed event
// Handled, so subscribe with handledEventsToo = true rather than a plain "+=".
Pego1.AddHandler(Microsoft.UI.Xaml.UIElement.PointerMovedEvent,
new Microsoft.UI.Xaml.Input.PointerEventHandler(Pego1_MouseMove),
true);Pego1.PeUserInterface.Cursor.Mode = CursorMode.DataCross;
Pego1.PeUserInterface.Cursor.MouseCursorControl = true;
Pego1.PeUserInterface.Cursor.MouseCursorControlClosestPoint = true;MouseCursorControlClosestPoint = true makes the crosshair cursor snap to
the nearest data point as the mouse moves, without requiring a click.
4 subsets × 24 monthly points (Jan 2023 – Dec 2024) of synthetic regional sales data:
| Subset | Series | Axis | Color |
|---|---|---|---|
| 0 | North | Left Y (units) | Cyan |
| 1 | South | Left Y (units) | Green |
| 2 | West | Left Y (units) | Red |
| 3 | Market Share | Right Y (%) | Gold |
| Input | Action |
|---|---|
| Mouse move | Status bar identifies element under cursor |
| Mouse hover | Tooltip shows both Y-axis values at cursor |
| Left-click drag | Zoom box |
| Right-click | Context menu — export, print, customize |
- Visual Studio 2026 with the .NET desktop development and Windows application development workloads
- .NET 10 SDK
- Internet connection for NuGet restore
No XAML designer: Visual Studio has no XAML designer for WinUI 3 in any edition, so the chart is declared in markup (
<pe:PegoWinUI x:Name="Pego1" />) rather than dragged from the Toolbox. That is a Windows App SDK limitation, not a ProEssentials one. Nothing needs to be installed beyond the NuGet packages for this project to build and run.
1. Clone this repository
2. Open MouseInteractionHotspots.sln in Visual Studio 2026
3. Build → Rebuild Solution (NuGet restore is automatic)
4. Press F5
References
ProEssentials.Chart.Net10.WinUI.
Package restore is automatic on build.
The AnyCpu package embeds the native rendering engines inside the assembly and
unpacks the one matching the running process at run time, so there is no native
DLL to copy or deploy alongside your app. It also carries the control's .pri,
whose resources are merged into your app's own .pri at build time.
The nuget.org package is the evaluation build and draws an "Evaluating ProEssentials" watermark across the chart. A licensed installation replaces the assembly and the watermark goes away — everything else behaves identically.
WinUI deploys differently than WPF and WinForms — worth knowing before you ship:
- A .NET app is not a single exe. Ship the entire build or publish output folder, never a hand-picked subset.
- The target machine needs two runtimes: the .NET 10 Desktop Runtime and
the Windows App SDK Runtime. Alternatively publish self-contained with
-p:WindowsAppSDKSelfContained=true. - Your development machine already has both, so it will run from an under-filled folder. Always validate on a clean machine.
- WPF version of this example
- WPF Custom Y-Axis Labeling
- WPF Heatmap Spectrogram
- All Examples — GigasoftInc on GitHub
- Full Evaluation Download
- gigasoft.com
Example code is MIT licensed. ProEssentials requires a commercial license for continued use.