Why would my HitTestResultCallback not be called - c#

I've inherited a program that uses hit testing to handle mouse events against a bunch of drawings on a canvas. Under some circumstances my HitTestResultCallBack stops being called.
Here's where the HitTest is called (this is called from the mousemove event):-
internal void HitTest(System.Windows.Input.MouseEventArgs e)
{
m_visualTrackerHit = m_visualTrackerHit2 = null;
Point location = e.GetPosition(this);
Geometry g = new RectangleGeometry(new Rect(location.X - m_connectDistance, location.Y - m_connectDistance, m_connectDistanceX2, m_connectDistanceX2));
HitTestParameters parameters = new GeometryHitTestParameters(g);
HitTestResultCallback callback = new HitTestResultCallback(this.HitTestCallback);
System.Diagnostics.Debug.Print("About to Hit Test");
VisualTreeHelper.HitTest(this, null, callback, parameters);
}
Here's my call back function:-
private HitTestResultBehavior HitTestCallback(HitTestResult result)
{
System.Diagnostics.Debug.Print("HitTestCallBack");
DrawingVisual visual = result.VisualHit as DrawingVisual;
if (visual != null)
{
VisualTracker visualTracker = visual.GetValue(FrameworkElement.TagProperty) as VisualTracker;
if (visualTracker != null && visualTracker.Type != VisualType.Selection && visualTracker.Type != VisualType.Ignore)
{
if (m_visualTrackerHit == null || visualTracker.Type < m_visualTrackerHit.Type)
{
m_visualTrackerHit = visualTracker;
}
}
}
return HitTestResultBehavior.Continue;
}
This all works fine until I take a particular, apparently unrelated action. (In this case each drawing represents a "component" that will have various properties. Setting a property to an invalid value causes the problem but this is all domain stuff and almost certainly isn't relevant to my question). Once that action is taken the call back method just stops being called. N.b. not just for the drawing the property was changed on either, the call back stops getting called for both the canvas and all the objects on it.
I've traced through the code path from the action and can't see anything obvious in there but it's highly complex and I could well have missed something so I'd like to come at this from the other direction. What are the possible reasons the callback wouldn't be called.
I've checked the following:-
The RectangleGeometry is being defined with correct values so it should indicate a collision with the drawing
Nothing is setting IsHitTestVisible to false anywhere.
Any suggestions?

I wanted to come back on this as I finally found the answer - or part of it at least. The property that was set to an invalid value on the component was causing a divide by zero error in the draw method of that component. That meant that the component was not redrawn but the old drawing of it was left in place, meaning it was not obvious that an error had occurred.
I've tested around this a bit and any unhandled error drawing to the canvas seems to result in the hitTestCallback no longer being called for anything on that canvas. I don't know why that is but it's easy for me to solve at this point as I can just guard against divide by zero exceptions

Debug your program using Snoop:
identify the path of events for a working case
identify the path of events for a non-working case
once you pinpoint the cause, you can come up with a fix for it

Related

Unable to load true type font in SharpDX

I've been trying to draw custom fonts in SharpDX. I basically followed the example from GitHub.
Whenever I try to draw the font using the D2D1 RenderTarget it throws the error below:
System.ObjectDisposedException: Cannot access a disposed object.
Object name: "Cannot add a reference to a nonreferenced item"
So after a long time of debugging I couldn't find where was the issue so I decided to try to compile the project from the example above and I got the exact same error (it outputs to debug console that there is a 'System.ObjectDisposedException' Exception in SharpDX.dll)
Edit: The exit code for the program is 3; it may be useful.
I concluded that the issue was from the library itself. In my opinion there is a low chance that it's the case but if the example itself there is surely something wrong here. I'm not too familiar with DirectX in general either so I won't refuse an advise or two.
Note that in what I saw, the font was correctly loaded in the TextFormat and TextLayout.
I tried to modify my code, remove Dispose() method, replaced my whole code with the one of the example and tried to find the root of the problem, without success. I'm expecting the DrawText method from the RenderTarget shouldn't throw such error and draw the text with the font I imported.
UPDATE: The example shown is for SharpDX 3.0.0, this explains why it does not work properly. But I still need to know how can I fix the issue for SharpDX 4.2.0
How can I fix this issue if possible?
The error basically means there's a COM object that has a refCount value that is down to 0, so it shouldn't be used anymore. The code is located in SharpDX's CallbackBase.cs:
public int AddReference()
{
var old = refCount;
while (true)
{
if (old == 0)
{
throw new ObjectDisposedException("Cannot add a reference to a nonreferenced item");
}
var current = Interlocked.CompareExchange(ref refCount, old + 1, old);
if (current == old)
{
return old + 1;
}
old = current;
}
}
So it's "just" a COM reference issue. The error is thrown by the CustomFont.ResourceFontFileStream.cs file that derives from CallbackBase (it's implements a COM object), so there's a reference issue on the ResourceFontFileStream type.
How SharpDX handles references in the general case is a bit obscure to me (it has lots of wrapper and boilerplate code) but you can fix it if you add a reference when a ResourceFontFileStream is given out by a COM method. This is how things are done normally in COM methods: when an out object is given back to the caller, the callee calls AddRef () on the object.
So, you can change the ResourceFontLoader.cs file, like this:
// this implements IDWriteFontFileLoader::CreateStreamFromKey https://learn.microsoft.com/en-us/windows/win32/api/dwrite/nf-dwrite-idwritefontfileloader-createstreamfromkey
FontFileStream FontFileLoader.CreateStreamFromKey(DataPointer fontFileReferenceKey)
{
var index = Utilities.Read<int>(fontFileReferenceKey.Pointer);
_fontStreams[index].AddReference(); // add this line
return _fontStreams[index];
}

Unity3D: Detect if mouse has clicked on a UI element?

This is a pretty simple question, but it seems something has changed on Unity in the last versions answers I've found on the internet are no longer valid, so here goes nothing:
I got some UI elements, and a "InputController" class which is intended to handle the user input during the game (Input on the controllers are handled through the onclick events).
What I'm looking is for a way to being able to know if the mouse is clicking a UI element to block the execution of my input handling (and avoid the user clicking on "pause" while also the game executes "left button clicked."
Now, most solutions I've fond were a bit messy or used EventSystem.current.IsPointerOverGameObject() (like this one, which was shown when writing this question), which in 2019.4 does not longer appear. So, there's any new way to do this, do I have to make some hacky solution to receive the event from the UI, then block the execution of my code or am I missing something here?
You should look into interfaces like IPointerEnterHandler and IPointerExitHandler. If you implement these interfaces for your UI elements, you can add the necessary code to the OnPointerEnter and OnPointerExit methods that those interfaces require.
It should be as simple as adding a bool to your InputController such as isInputEnabled and only handling input when that is true. Set it to false OnPointerEnter and true OnPointerExit.
I spent a good amount of time trying to figure this out as well. I am on Unity 2022.1 using the Input System and UI Toolkit (UI Elements)
The following should help anyone else who is struggling with this to get the behavior they need.
Examine your UI Documents
You don't want your UI Document to always report clicks. So you need to set the picking mode in your UXML documents accordingly. Have a look at the images below,
In the image on the left, I have a wrapping element that allows me to position the panel at the bottom of the document. By default this element will receive all pointer events. What I actually want is to only receive pointer events inside of the orange area seen in the image on the right.
I can fix this by setting the picking mode of all parent elements to ignore:
Set up the input system
Setting up the new input system is a topic in itself. Refer to the documentation for more information, but in the image you can see I am using a simple button event as a click/tap action:
Set up your script
Next you need to respond to the input action and check if your input is seen by the UI
public class SimpleInput : MonoBehaviour
{
public Camera ViewCamera;
private PlayerControls _controls;
private void OnEnable()
{
Assert.IsNotNull(ViewCamera, "ViewCamera cannot be null");
// This class will vary depending on the name of your Input Action Asset
_controls = new PlayerControls();
_controls.Enable();
_controls.Gameplay.TapAction.performed += OnInputTapAction;
}
private void OnInputTapAction(InputAction.CallbackContext obj)
{
Vector2 position = Pointer.current.position.ReadValue();
Ray ray = ViewCamera.ScreenPointToRay(position);
if (PointerIsUIHit(position))
{
Debug.Log("Ui event received");
}
else
{
// Perform game-world events here
}
}
private bool PointerIsUIHit(Vector2 position)
{
PointerEventData pointer = new PointerEventData(EventSystem.current);
pointer.position = position;
List<RaycastResult> raycastResults = new List<RaycastResult>();
// UI Elements must have `picking mode` set to `position` to be hit
EventSystem.current.RaycastAll(pointer, raycastResults);
if (raycastResults.Count > 0)
{
foreach (RaycastResult result in raycastResults)
{
if (result.distance == 0 && result.isValid)
{
return true;
}
}
}
return false;
}
}
The helper method PointerIsUIHit was inspired by a conversation found in the Unity Forums which had some insight into how to get this done. It also shed some insight into the frustrating experience of being a Unity Dev.
Hopefully this helps other people struggling to find a proper guide.

Catch does not perform its code

I'm developing C# application for windows phone 8.1 (Silverlight). Lately I've came across the problem connected to application falling asleep and storyboards.
The construction goes as follows:
class X : DependencyObject
{
public static readonly DependencyProperty vProperty =
DependencyProperty.Register("v", typeof(double), typeof(X), new PropertyMetadata(0.0));
public double v
{
get
{
return (double)GetValue(vProperty);
}
set
{
SetValue(vProperty, value);
}
}
private Storyboard _storyboard;
void Prepare()
{
_storyboard = new Storyboard();
var animation= new DoubleAnimation
{
From = 0,
To = 1,
BeginTime = 0,
Duration = 0,
};
_storyboard.Children.Add(animation);
Storyboard.SetTarget(animation, this);
Storyboard.SetTargetProperty(animation, vProperty);
}
void Go()
{
_storyboard.Begin();
}
}
There is a NullReferenceException thrown from inside of _storyboard.Begin() if application is placed in background between "Prepare" and "Go" (about 10% reproduction rate). Of course it ends up with crash.
I was not able to determine problem source and as I need quickfix for that I've decided to just catch this NullRefereneceException in this rare scenario. This is where real question starts. I've changed "Go" implementation to:
public void Go()
{
Debug.WriteLine("BreakPoint 1");
try
{
_storyboard.Begin();
}
catch (NullReferenceException)
{
Debug.WriteLine("BreakPoint 2");
}
}
Afterwards the crash is not reproducible at all, but the problem is that "BreakPoint 2" is never hit (no printout in Output either). "BreakPoint 1" is normally hit and printed as well. Changing NullReferenceException to other Exception type (not parent type ofc) causes crash to reappear.
So... What's going on here? Is this crash cached or not? What kind of weird behavior is that? Is it safe to assume that it will work as expected?
Additional question: Maybe you know why the original code crashes in the first place?
EDIT:
End of stack trace of internalException of TargetInvocationExceptions looks as follows:
at MS.Internal.XcpImports.CheckHResult(UInt32 hr)
at MS.Internal.XcpImports.Storyboard_Begin(Storyboard storyboard)
at System.Windows.Media.Animation.Storyboard.Begin()
at X.Go()
I know that you've said that you've tried to use parent types for NullReferenceException, but please try the following without running in the debugger:
public void Go()
{
Debug.WriteLine("BreakPoint 1");
try
{
_storyboard.Begin();
}
catch (Exception)
{
Debug.WriteLine("BreakPoint 2");
System.Diagnostics.Debugger.Break();
}
}
My suspicion is that the catch is not firing because you are running from within the debugger. Also try System.Diagnostics.Debugger.Launch(); in the catch if .Break(); does not work. And finally also try throw; in the catch if .Launch(); does not work.
If the debugger attempts to launch in either case, then you have another clue.
UPDATE:
I can't give you all of the reasons why this might happen as it may not be possible to determine precisely what is causing it in your situation.
I've seen behavior like this due to use of multithreading. Multithreading can behave differently when running with a debugger attached then without. Timing issues and race conditions can prevent exceptions from being thrown while in the debugger that otherwise may occur frequently when there is no debugger attached.
I've also encountered instances where System.Diagnostics.Debugger.IsAttached was used in third party code and even my team's code which caused the application to behave differently based on if statements using this check.
And lastly, I've had times where I could not come up with a specific reason why the behavior was occurring. I've learned to use the System.Diagnostics.Debugger.Break() method whenever I see behavior exhibited differently depending on whether a debugger is attached or not. Sometimes it really is just a gut feeling.

Mouse-state suddenly broke in my project.

This is the most unusual error ever!
I am using XNA(Monogame) and using the following code to get the mouse state:
Mousestate ms = Mouse.GetState();
Then I could check for clicks with the following:
if(ms.RightButton == ButtonState.Pressed)
{
}
Or check for scroll by setting a previous scroll variable and compare it to the current one.
All was working well, until I was working on my system today, and I tested it and all mouse interaction stopped working. But keyboard state did work.
I thought it could be because it was not getting called or was not being checked.
So I placed this is my working update method.
if (ms.LeftButton == ButtonState.Pressed)
{
throw new NullRefrenceException();
}
I tried Left clicking and nothing happened. Made sure it was not something else by removing the if-statement and sure enough it did throw it.
So after being desperate I created a Windows Mono-game Proj and put the same code into the update method.
I left-clicked and the error was thrown sure enough.
I have tried commenting out every line of code which has the word ms/mouseState/Mouse. And only leaving one, but to no avail.
I would create a Minimal, Complete, and Verifiable Example but my project is very large, and I have declared Mouse-state in over 30 classes.
I have tried restarting computer, restarting visual-studio, ending all vs/vs-host processes, using a different mouse and lots of code tweaking.
No errors are thrown, when I try and use break-point near Mouse-state it is not set to null.
If any further information is needed for this question, please say so.
Well. If you initialize Game1.
Game1 g1 = new Game1();
It will break mouseState.
If a class extends : Microsoft.Xna.Framework.Game
And uses its methods. If you initialize it again it will break.
Game1 should not be initialized.

Stack overflow after an exception in Control.LayoutUpdated if DispatcherUnhandledException is registered

Recently, I was running into a problem which I'm still breaking my head over. In an application, I registered a dispatcher exception handler. In the same application, a third-party-component (DevExpress Grid Control) causes an exception within the event handler for Control.LayoutUpdated. I expect, that the dispatcher exception handler is triggered once. But instead, I get a stack overflow. I produced a sample without the third party component and discovered, that it happens in every WPF application.
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
namespace MyApplication
{
/* App.xaml
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="MyApplication.App"
Startup="OnStartup"
/>
*/
public partial class App
{
private void OnStartup(object sender, StartupEventArgs e)
{
DispatcherUnhandledException += OnDispatcherUnhandledException;
MainWindow = new MainWindow();
MainWindow.Show();
}
private static void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
MessageBox.Show(e.Exception.Message);
e.Handled = true;
}
}
public class MainWindow : Window
{
private readonly Control mControl;
public MainWindow()
{
var grid = new Grid();
var button = new Button();
button.Content = "Crash!";
button.HorizontalAlignment = HorizontalAlignment.Center;
button.VerticalAlignment = VerticalAlignment.Center;
button.Click += OnButtonClick;
mControl = new Control();
grid.Children.Add(mControl);
grid.Children.Add(button);
Content = grid;
}
private void OnButtonClick(object sender, RoutedEventArgs e)
{
mControl.LayoutUpdated += ThrowException;
mControl.UpdateLayout();
mControl.LayoutUpdated -= ThrowException;
}
private void ThrowException(object sender, EventArgs e)
{
throw new NotSupportedException();
}
}
}
Is there any way to prevent this behavior? It happens with .NET framework 3.0, 3.5, 4.0 and 4.5. I can't just wrap a try-catch around the LayoutUpdated event handler since it is in a third party component and I don't think, a stack overflow should happen.
I think Florian GI is right about the message box, but if instead of a message box you did something else (or nothing i.e. just set Handled to true) in the OnDispatcherUnhandledException method it still loops forever and doesn't get to the mControl.LayoutUpdated -= ThrowException; line.
So I thought I would have a little snop through the code with dotPeek...
When you call UpdateLayout on the control, ultimately it gets to the method ContextLayoutManager.UpdateLayout and a snippet of this method looks like this:
// ... some code I snipped
bool flag2 = true;
UIElement element = (UIElement) null;
try
{
this.invalidateTreeIfRecovering();
while (this.hasDirtiness || this._firePostLayoutEvents)
{
//... Loads of code that I think will make sure
// hasDirtiness is false (since there is no reason
// for anything remaining dirty - also the event is
// raised so I think this is a safe assumption
if (!this.hasDirtiness)
{
this.fireLayoutUpdateEvent();
if (!this.hasDirtiness)
{
this.fireAutomationEvents();
if (!this.hasDirtiness)
this.fireSizeChangedEvents();
}
}
//... a bit more
flag2 = false;
}
}
finally
{
this._isUpdating = false;
this._layoutRequestPosted = false;
//... some more code
if (flag2)
{
//... some code that I can't be bothered to grok
this.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, (Delegate) ContextLayoutManager._updateLayoutBackground, (object) this);
}
}
// ... and for good measure a smidge more code
I'm going to take a punt and suggest that the _firePostLayoutEvents flag is true in your case.
The only place where _firePostLayoutEvents is set to false is in the fireAutomationEvents method so let's assume that somewhere before the end of the fireAutomationEvents method your exception is thrown (I would guess the fireLayoutUpdateEvent method) so this flag will not get set to false.
But, of course, the finally is outside the loop so it will not loop forever (and if it did you'd not get a StackOverflowException).
Right, onward, so we are invoking the UpdateLayoutBackground function, which actually just calls NeedsRecalc so let's look at that...
private void NeedsRecalc()
{
if (this._layoutRequestPosted || this._isUpdating)
return;
MediaContext.From(this.Dispatcher).BeginInvokeOnRender(ContextLayoutManager._updateCallback, (object) this);
this._layoutRequestPosted = true;
}
Rightyho, that is calling the UpdateLayoutCallback so squinting at that...
private static object UpdateLayoutCallback(object arg)
{
ContextLayoutManager contextLayoutManager = arg as ContextLayoutManager;
if (contextLayoutManager != null)
contextLayoutManager.UpdateLayout();
return (object) null;
}
Oooooh, that is interesting - it's calling UpdateLayout again - I would, therefore, hazzard a slightly educated guess that that is the root cause of your problem.
Therefore, I don't think there is anything much you can do about it I am afraid.
I am not quite sure about the following, but maybe it's a guess in the right direction.
In MSDN it sais:
However, LayoutUpdated can also occur at run time during the object
lifetime, for a variety of reasons: a property change, a window
resizing, or an explicit request (UpdateLayout or ApplyTemplate).
So it might get also fired after a MessageBox has shown?
If thats the case a MessageBox would open through an unhandled exception, which fires the LayoutUpdated-EventHandler and this again raises an unhandled exception. This would lead to an endless loop and after a while to the stack overflow.
If you do not throw an unhandled exception in the LayoutUpdated-EventHandler, but call the MessageBox.Show()-method it also ends in an endless loop, what would proof my point.
I realize I'm over four years late to the party, but maybe someone will find this useful...
Your application's dispatcher does not stop responding to input and layout events during the call to MessageBox.Show(). The LayoutUpdated event fires any time there is any layout-related work to do, which happens far more often than you might expect. It will continue to fire while the message box is displayed, and if whatever condition triggered the error continues to persist, new exceptions will be raised, and your handler will show more and more message boxes. And because MessageBox.Show() is a blocking call, it's not going to disappear from the call stack until it returns. Subsequent invocations of your handler will be pushed deeper and deeper into the dispatcher's call stack until it overflows.
You really have two separate problems:
Your code to display a crash dialog is reentrant.
Your application continues to raise exceptions on the dispatcher thread while your crash dialog is being displayed.
You could solve the first issue with a non-reentrant queue. Rather than displaying the crash dialog immediately, have your handler place the exception in a queue. Have your handler process the queue only if you are not already processing it farther up the stack. This prevents multiple crash dialogs from being shown simultaneously, and should keep your call stack from growing too deep, thus avoiding your stack overflow issue.
To address the second problem, you should probably shut down the offending part of your application as soon as you see the first exception (and before you show the crash dialog). Alternatively, you could devise a way to filter out duplicate exceptions and ensure that equivalent errors don't end up in the queue at the same time. But given how rapidly the exceptions are recurring, I would choose the first option.
Keep in mind that you need to address both of these issues. If you don't address the second issue, you'll likely end up trading in your StackOverflowException for an OutOfMemoryException. Or you'll show an infinite number of crash dialogs, one after the other. Either way, it'll be bad.

Categories

Resources