Issue:
Our application crashes when a user type some text into the WPF TextBox.
Please help! The easy 3 minutes reproduction appears below
Reproduction:
Register a WPF TextBox (m_textBox) TextChanged event to the method below
private void OnTextChanged(object sender, TextChangedEventArgs e)
{
// This line of code throws Unhandled exception when typing '^' char in
// the text box (in United "States-International" keyboard)
m_textBox.Dispatcher.Invoke(DispatcherPriority.Normal, new SendOrPostCallback(Foo), null);
}
private void Foo(object state)
{
//Do nothing
}
Change your keyboard to "United States - International"
Run the application and type '^' twice in the TextBox
Aplication will crash!!!!
The problem is the composition code doesn't expect to get additional input events until your TextChanged handler returns. When you call Dispatcher.Invoke, it causes the Windows message queue to be processed causing additional input events.
In my opinion this is a bug because the composition engine should be robust against re-entrancy when firing user-specified events.
I could reproduce this error. Typing ^q or ~~ will also cause the crash.
The exception that is thrown states that composition has already been completed. I managed to work around it by using the async BeginInvoke instead of Invoke. Will that work for you?
m_textBox.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new SendOrPostCallback(Foo), null);
Related
I have a window with a textbox that is not throwing textInput events when typing.
I have been looking at it with Snooper. Only the KeyDown and KeyUp events get thrown.
It IS responding to a few keys: Space, backspace, Insert, home, delete, end
It responds to copy & paste commands, as well as Select All
It is NOT responding to any character, symbol or number
And here's the kicker: This window is opened via a shared method that is called from two different places in the code. When called from one location the textbox works perfectly, when called from other location it doesn't.
I have ruled out binding, data converters, styles, control location.
I stripped the window down to just a single plain textbox with no bindings, and the problem persists.
I've tried all I can think of to track down this mysterious bug. I can't see what could be handling my event before the previewTextInput even gets throw, or why it could possibly be only occurring half the time.
Any ideas about the cause of this bug, or other tools I could try to trace the events would be greatly appreciated!
Edit: Adding some code to demonstrate. This has been stripped down to the barest code required, and the issue is still occurring.
<Window x:Class="EventViewEmail"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="880" Height="600">
<TextBox VerticalAlignment="Top"/>
</Window>
notice the lack of bindings, styles, or anything else that may be interfering the control
Public Class EventViewEmail
'all code removed from the view-behind'
End Class
this is the static class that builds the window. The two separate calls to this class build the arguments differently. I've removed the code that uses the arguments to show that they aren't affecting the issue at hand.
Public Class EventManager
Public Shared Sub Show(e As EventEdit, p As WorkplanPageViewModel)
Dim w = New EventViewEmail
If w Is Nothing Then Return
'removed datacontext for testing'
'w.DataContext = e '
'w.Tag = p'
w.Show()
End Sub
End Class
The only other thing I can add is that the code calling the Show() sub are coming from two separate solutions. Not sure what impact that could possibly have after I've removed all the arguments
Edit 2:
I have been trying to trace the events sequence to narrow down where the event is getting handled. So far I can see that between the keyDown and keyUp events, there is a sequence of events that should be happening that isn't:
PreviewInputReport / InputReport (no source)
PreviewTextInputStart / TextInputStart (textbox)
PreviewTextInput / TextInput (textbox)
PreviewInputReport / InputReport (textboxView)
the keydown event isn't being handled, so I'm not sure why the PreviewInputReport is not getting fired
Disclaimer
I'll post C# code because I'm not fluent enough in VB to write code (only to read it in a limited scope). I'll try to translate it if I find some time, or anyone of you can feel free to do it.
I have managed to reproduce the behavior you described by handling the PreviewTextInput event up the visual tree on the window (remember it's a tunneling routed event):
<Window (...)>
<StackPanel>
<TextBox x:Name="myTextBox"></TextBox>
</StackPanel>
</Window>
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
PreviewTextInput += (s, e) => e.Handled = true;
}
}
So in my opinion it's a strong suspect for the cause of your problems. It also explains the comment to #AQuirky's answer that your PreviewTextInput handler is not called. You can confirm that that's the case by subscribing differently (the handler is called even if the event was marked as handled):
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
PreviewTextInput += (s, e) => e.Handled = true;
myTextBox.AddHandler(
routedEvent: PreviewTextInputEvent,
handler: new TextCompositionEventHandler((s, e) =>
{
if (e.Handled)
throw new Exception("Gotcha!");
}),
handledEventsToo: true);
}
}
If this turns out to be correct diagnosis, then there's one thing that's somewhat mysterious - who and where does handle the PreviewTextInput event? I guess that's for you to investigate...
This comment from #l33t might come in handy:
Look for global event handlers like EventManager.RegisterClassHandler(typeof(TextBox), UIElement.PreviewTextInputEvent, ...) and/or behaviors. Are you using any third-party UI library? Look in their code as well.
Update
Since it seems like PreviewTextInput is not the culprit after all, here's what I'd do next.
If I'm not mistaken, there's a whole chain of events being fired prior to TextInputEvent, and I believe handling any of those can break the chain. It also looks like InputManager is responsible for managing this event cycle (you can inspect its C# source code here).
That being said I suggest doing the following:
Using InputManager.Current subscribe to its PreProcessInput and/or PostProcessInput events (optionally also PreNotifyInput and PostNotifyInput)
Record the events chain in the working scenario (especially inspect the args' StagingItem.Input.RoutedEvent, which holds the routed event currently being processed)
Repeat the procedure for the not working scenario
Pinpoint the first difference - the first routed event being processed in the working scenario, but not being processed in the not working scenario
Investigate both last common routed event and the first one that's different - perhaps one of those is handled in your code?
In this case it turned out that the form that launched the window in the not working case was a winform. The winform was blocking the keystrokes. This was fixed by opening the window as a modal.
I had the same problem here. The difference between the two calls was: one time the WPF-Windows was called modal (works) and one time nonmodal (doesnt work), everytime from a WindowsForms Window.
As Shaboboo wrote in his anwer, this is the difference, but what, if you need to call nonmodal.
The answer is given this thread. (stupid me, I had the same problem 2 years ago, asked and got an answer). We have to use
ElementHost.EnableModelessKeyboardInterop(wpfWindow);
Thanks again to V.Leon
The problem is that while the TextInput is being fired (not thrown...exceptions are thrown) you are not seeing it because the text box itself is using it. To catch this event you need to use the PreviewTextInput. So for example
<TextBox TextInput="UIElement_OnTextInput" PreviewTextInput="UIElement_OnPreviewTextInput"></TextBox>
With event handlers...
private void UIElement_OnTextInput(object sender, TextCompositionEventArgs e)
{
Console.WriteLine($"In text input event, {e.Text}");
}
private void UIElement_OnPreviewTextInput(object sender, TextCompositionEventArgs e)
{
Console.WriteLine($"In preview text input event, {e.Text}");
}
The first handler is never called, the second one always.
Your handler is not called because other handlers have marked the event as handled. You can add an handler with AddHandler() and pass true for the third argument:
public MainWindow()
{
var handler = new RoutedEventHandler(OnTextInput);
myTextBox.AddHandler(TextInputEvent, handler, handledEventsToo: true);
}
private static void OnTextInput(object sender, RoutedEventArgs e)
{
}
I have made a textbox and I want the user to type in a string of numbers and hit enter. I have setup the following:
private void textBox1_TextChanged(object sender, EventArgs e)
{
String UserBarcode;
Focus();
UserBarcode = Console.ReadLine();
MessageBox.Show(UserBarcode);
}
When I enter any key into the textbox, I get a message box with nothing in it. I want to have the program wait til it hears the enter key then display the contents of the textbox.
The Textbox.TextChanged event fires as soon as the text in the textbox is changed at all. If you want a message box with the full string, you probably want to consider using the Textbox.LostFocus event or a button's Click event.
So you could have something like (I'm taking a stab at this here, as I've used VB rather than C#)
private void textBox1_LostFocus(object sender, EventArgs e)
{
MessageBox.Show(sender.Text)
}
If you're using a button, the above function should work, but you'll want to substitute textBox1.Text for sender.Text.
Take a look at Focus and Validation Events
There are several events that you can handle, depending on your goals and how your application is designed. If you want to perform validation and/or are using data binding, you may want to go with handling the validating/validated events. By default data bindings update a bound property after OnValidating. If you use LostFocus and read the value from a bound object, instead of your control, you will get inconsistent results.
I was able to figure it out finally. For some reason when I manually entered the code I kept getting multiple random errors. I started a new Visual C # Windows Forms Application, Made a textbox, chose the keydown property and double clicked on it to have the program inject the code for the keydown function and then I filled in the if statement pointing to the enter key. The final code looks like this:
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
MessageBox.Show(textBox1.Text);
}
}
I'm trying to create a simple global exception handler in a WPF application that is build with the MVVM Light Toolkit, but I'm having a hard time making it work.
The thing is that an exception risen in a view model will not be caught in the App's UnhandledException handler, even though I register a listener for both the Dispatcher and the AppDomain like this:
private void Application_Startup(object sender, StartupEventArgs e)
{
AppDomain.CurrentDomain.UnhandledException += DomainUnhandledException;
DispatcherUnhandledException += App_DispatcherUnhandledException;
}
private void DomainUnhandledException(object sender, UnhandledExceptionEventArgs unhandledExceptionEventArgs)
{
var exception = unhandledExceptionEventArgs.ExceptionObject as Exception;
ShowExceptionMessage(exception);
}
private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
ShowExceptionMessage(e.Exception);
e.Handled = true;
}
I found this blog post that describes the problem spot on, with the solution described with this code snipped for view models:
// Throw the exception in the UI thread.
App.Current.RootVisual.Dispatcher.BeginInvoke(() => { throw new MyException(); });
However, I would like all exceptions to bubble up to the global exception handler, not only the ones that I throw myself in the VM.
So the question is: Is it somehow possible to re-throw exceptions from other threads into the UI thread in one place?
Update: Added more detailed code for the App's event handler setup.
I think I figure this out now.
The problem is due to the fact that WPF suppresses exceptions thrown in a view's databinding, and because my view model is databound to the view's DataContext (through a property in my ViewModelLocator utilizing unity dependency injector) any exceptions in the construction of the view model will be swallowed.
See this SO question for more info.
So I suppose I just have to make sure that nothing important for the application's ability to function correctly should happen in the constructor.
The “global” exception handling events for WPF and Windows Forms applications (Application.DispatcherUnhandledException and Application.ThreadException) fire only for exceptions thrown on the main UI thread. You still must handle exceptions on worker threads manually.
AppDomain.CurrentDomain.UnhandledException fires on any unhandled exception, but provides no means of preventing the application from shutting down afterward.
Maybe check also Thread Pooling “divide-and-conquer” style.
TPL
How do I invoke a method on the UI thread when using the TPL?
A WPF window dialog is shown using the ShowDialog method in the Window class like when a button is pressed on the main window, like this.
private void button1_Click(object sender, RoutedEventArgs e)
{
try
{
var window = new Window1();
window.ShowDialog();
}
catch (ApplicationException ex)
{
MessageBox.Show("I am not shown.");
}
}
The window has a Loaded event subscribed in the xaml like this:
<Window x:Class="Stackoverflow.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Loaded="Window_Loaded">
<Grid />
</Window>
An exception is thrown in the Window_Loaded event
private void Window_Loaded(object sender, RoutedEventArgs e)
{
throw new ApplicationException();
}
However the exception is not catched by the catch around the ShowDialog call, nor does the call return. The exception is swallowed and the window still displayed.
Why does this happen and how would I go about handling an exception in the Window_Loaded event of a WPF window? Do I have to catch it in the event-handler and Dispose the window manually?
In WinForms you need to call Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException)
in order to let exceptions bubble through ShowDialog calls. Is there a similar switch that needs to be set on WPF?
I've only seen this issue on x64 machines, with code compiled with Any Cpu.
Changing your program to compile as x84 may fix it, but I've had problems there myself depending on our assemblies.
My only code suggestion is the following, and even then it's not guaranteed to pick it up.
Catch the exception, and re-throw it in a Background worker.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
try
{
/// your code here...
throw new ApplicationException();
/// your code here...
}
catch (Exception ex)
{
if (IntPtr.Size == 8) // 64bit machines are unable to properly throw the errors during a Page_Loaded event.
{
BackgroundWorker loaderExceptionWorker = new BackgroundWorker();
loaderExceptionWorker.DoWork += ((exceptionWorkerSender, runWorkerCompletedEventArgs) => { runWorkerCompletedEventArgs.Result = runWorkerCompletedEventArgs.Argument; });
loaderExceptionWorker.RunWorkerCompleted += ((exceptionWorkerSender, runWorkerCompletedEventArgs) => { throw (Exception)runWorkerCompletedEventArgs.Result; });
loaderExceptionWorker.RunWorkerAsync(ex);
}
else
throw;
}
}
The "Why" is explained here: http://blog.paulbetts.org/index.php/2010/07/20/the-case-of-the-disappearing-onload-exception-user-mode-callback-exceptions-in-x64/
In short, the exception cannot be propagated in 64-bit operating systems because there is a transition between user and kernel mode.
The test of IntPtr.Size in #midspace answer is not adequate because IntPtr.Size will be equal to 4 in an x86 process running on a x64 os (you need to use Environment.Is64BitOperatingSystem instead on .NET 4 and greater).
The solution now: use another event like ContentRendered which is called after the Loaded one or put your code in the window constructor.
Never use Loaded (or OnLoad in Winforms), because if there is an exception there, you don't know what can happens.
Have a look also at this answer: https://stackoverflow.com/a/4934010/200443
I also reconstructed your answer in Visual Studio 2010 in a blank WPF 3.5 project.
The project behaved as expected, i.e. the Window_Loaded threw the exception, and it was caught by the button click event.
So I'm not sure why yours isn't working, maybe try posting your App.xml.cs and any other code you haven't shown here?
In the meantime, I thought I would point out a few things:
WPF does indeed handle "uncaught" exceptions a little differently from WinForms. Try looking at this for a starter:
http://msdn2.microsoft.com/en-us/library/system.windows.application.dispatcherunhandledexception.aspx
It looks as if there isn't an exact equivalent in WPF for the SetUnhandledExceptionMode method (See http://social.msdn.microsoft.com/forums/en-US/wpf/thread/955c75f8-9cd9-4158-bed9-544bd7946413). Try their advice about registering a handler and see if that helps you?
I would recommend stepping through your code - set a breakpoint in the Window_Loaded, and see what happens - pay careful attention to the call stack.
Good luck!
Researching this a bit more I found this peculiar blogg entry describing a similar problem.
http://blog.paulbetts.org/index.php/2010/07/20/the-case-of-the-disappearing-onload-exception-user-mode-callback-exceptions-in-x64/
As it turns out it might be a 64-bit processor architecture problem. Who would have guessed?! It might explain why some people could not reproduce the issue my simple example. I tried to compile my example in "Any CPU", x64 and x86 but to no avail. On x64 the whole thing actually blew up completely crashing with a windows crash dialog.
So I guess this is the answer without verifying it on a 32-bit machine.
I've had similar problem, and trying to understand where it's coming is frustrating. There's a couple of things that could be causing a problem.
Are you calling anything before the method call InitializeComponent(); ? Previously I've had a method calling xaml elements, which haven't been initialised yet.
Have you tried pressing F10 to start the application, using Step Over will let you see the exact process start up?
Have you checked your naming? XAML can swallow errors such as methods being mis-spelt, and then an exception is thrown on run time, this particularly true DataSet providers. You'd be surprised what you can get away with.
Catching an exception for opening a form is pretty fundamental, I'd rather look at any dependents (Data or XAML bindings) and deal with those first.
Hope those points help.......
I'm creating a simple editor within our application using the WPF RichTextBox. Above it I've added the reguslar buttons like Bold, Italic, etc. These buttons use the RichTextBox's commands to set these properties, but next to these buttons, the commands also get send with CTRL+B, CTRL+I, etc. I want these buttons to represent the current state of the RichTextBox at the cursor. I already found out how to get this state and it works when I update this state on the SelectionChanged event. This event ofcourse isn't fired when Bold is toggled so there is no direct feedback.
I would like to know if there is a way to listen to the commands being called, without affecting its original behaviour or some other ideas to solve my problems.
I tried listening to the command the following way:
CommandBinding boldBinding = new CommandBinding(EditingCommands.ToggleBold, CommandExecuted);
_richTextBox.CommandBindings.Add(boldBinding);
and
private void CommandExecuted(object sender, ExecutedRoutedEventArgs e) {
UpdateProperties();
e.Handled = false;
}
This did update the properties, but the RichTextBox didn't seem to receive the command anymore.
I also tried to make my own commands on the control containing the RichTextBox, but when CTRL+B is pressed when the RichTextBox has focus, the original RichTextBox commands are called instead of the new one.
Many thanks in advance!
Liewe
In order to listen to the commands being called, you can use the events raised by CommandManager: Executed or PreviewExecuted.
If you change your XAML to:
<RichTextBox x:Name="_richTextBox" ...
CommandManager:PreviewExecuted="OnRichTextBoxCommand" ... />
you get the OnRichTextBoxCommand method called right before the command is executed. Unfortunately, using the Executed attached event does not work.
This method is called for each event, so you have to filter them:
private void OnRichTextBoxCommand(object sender, ExecutedRoutedEventArgs e) {
if (e.Command == EditingCommands.ToggleBold) {
UpdateProperties();
}
}
It may be even a bit more complex, as the current selection may not have changed when this method is called, so you have to post yourself a message, e.g. like this:
Dispatcher.BeginInvoke(new Action(UpdateProperties));
(if you reference already System.Core, you have the Action type, otherwise define a delegate taking no parameter and returning void, and use in instead.)