Hello,
I am developing an ArcGIS Pro SDK MapTool in C#.
I want to change the mouse cursor depending on whether the current mouse position is on a selected polygon feature or not.
For example:
At first, I implemented the check inside `OnToolMouseMove` using `QueuedTask.Run`, something like:
protected override void OnToolMouseMove(MapViewMouseEventArgs args)
{
_ = QueuedTask.Run(() =>
{
var mapPoint = MapView.Active.ClientToMap(args.ClientPoint);
bool isHit = GeometryEngine.Instance.Intersects(_selectedGeometry, mapPoint);
Cursor = isHit ? Cursors.Hand : Cursors.Cross;
});
base.OnToolMouseMove(args);
}However, this caused noticeable lag.
It looks like `QueuedTask` calls keep getting queued during mouse movement, and cursor updates become delayed.
I improved the behavior by preventing multiple simultaneous cursor checks and only processing the latest mouse position, but I still have these questions:
For context, the selected geometry may sometimes include multiple polygons, and possibly polygons with holes, so replacing the hit-test with a very rough custom approximation is not always ideal.
If anyone has sample code, recommendations, or experience with this kind of cursor handling, I would appreciate it.
Thank you.
Hey there,
Traditional OnToolMouseMove tricks wont work here but you can use some Task secret sauce (TaskCompletionSource).
private Geometry _firstSelectedGeometry = null;
private TaskCompletionSource<MapPoint> _tcs;
private System.Windows.Point _lastClientPoint;
private bool _processing = false;
protected override void OnToolMouseMove(MapViewMouseEventArgs args)
{
_lastClientPoint = args.ClientPoint;
// If a conversion is already in progress, don't start another
if (_processing)
return;
_processing = true;
_tcs = new TaskCompletionSource<MapPoint>();
QueuedTask.Run(() =>
{
var mapPoint = MapView.Active.ClientToMap(args.ClientPoint);
_tcs.TrySetResult(mapPoint);
});
// Continue on UI thread when MCT finishes
_ = HandleMapPointAsync();
base.OnToolMouseMove(args);
}
private async Task HandleMapPointAsync()
{
try
{
var mapPoint = await _tcs.Task;
bool isHit = GeometryEngine.Instance.Intersects(_firstSelectedGeometry, mapPoint);
Cursor = isHit ? Cursors.Hand : Cursors.Cross;
}
finally
{
_processing = false;
}
}
Why this works
If you have complex geometry you could still do a pre-hit test with the evelope (.Contains) but this may not be required.
Ps. This is not definitive Esri code....