Troubleshooting a XAML error in WPF
I recently helped troubleshoot a WPF application that was causing an unhandled exception. I thought the process of identifying and fixing the problem might be useful to others and decided to describe it in this post.
The problem occurred when the user clicked on an item in a list to open a detail window with more information. At that point, the application displayed a message box with the following error and quit:
'Provide value on 'System.Windows.StaticResourceExtension' threw an exception.' Line number '9' and line position '10'.
The message box was opened by the following code in the application's unhandled exception handler:
public partial class App : Application
{
public App()
{
DispatcherUnhandledException += App_DispatcherUnhandledException;
}
private void App_DispatcherUnhandledException(
object sender,
DispatcherUnhandledExceptionEventArgs e)
{
var exception = e.Exception;
e.Handled = true;
Debug.WriteLine(exception.ToString());
MessageBox.Show(exception.Message);
Shutdown();
}
}
Although it may not look like it, the message contains a lot of useful information that can help you find the problem:
The namespace of the class throwing the exception (
System.Windows
) belongs to WPF. This means that the error occurs at the UI level.StaticResourceExtension
is the underlying class for theStaticResource
markup extension used in the binding. This means that the error originates in a XAML file. You should look for something like the following:<Button Style="{StaticResource ButtonStyle}" Content="Button"/>
The specified line number and position should point to the element with the incorrect
StaticResurce
markup extension in the XAML file. Of course, in a large WPF application, there are numerous XAML files and the problem could originate from any of them that is involved in rendering the erroneous part of UI. Nevertheless, if you know that aStaticResource
markup extension should be present at the specified location in the file, you can greatly narrow down the list of possible files.
Once you have found the correct file, it is very likely that the Visual Studio XAML editor has already detected the problem and marked the problematic attribute with a squiggly line:
Once you have identified the possible cause of the error, you can first try to remove it and make sure that the error has disappeared afterwards. After confirming this, you can reinsert the removed markup and fix the error properly. In this particular case, you will most likely need to correct the typo in the resource name or add the missing resource.
In my case, the steps described above were sufficient to find the error. Below are some other suggestions that often help find the cause of an error:
An exception contains more information than just the
Message
property. To see all the information, you should read the output of theToString()
method instead of theMessage
property. You probably do not want to show this to the user (nor should theMessage
property normally be shown to the user), but you can log it instead. Or at least print it out during development:Debug.WriteLine(exception.ToString());
In the example error from this post, the exception contains an inner exception that names the missing resource name (the text above is followed by a full stack trace, which is not useful in this case because it comes from the internal WPF implementation):
System.Windows.Markup.XamlParseException: 'Provide value on 'System.Windows.StaticResourceExtension' threw an exception.' Line number '9' and line position '10'. ---> System.Exception: Cannot find resource named 'ButtonStyle'. Resource names are case sensitive.
Make sure you check all the information in the Visual Studio exception dialog. Even though it looks scary at first glance, it contains the same complete information about the exception that is returned by the
ToString()
method. Just make sure that you resize the dialog so that you can see all the text.If you are not sure exactly where in a block of code or markup the error might be, you can try removing or commenting out the entire block. If you can still reproduce the error after that, the error is probably somewhere else. However, if the error has disappeared, the cause is probably somewhere in that block. You can then remove a smaller block and repeat the experiment until you find the culprit using the bisection method.
Git can also be of great help to you in finding the change that caused the error. Even if you are working on a project yourself or just learning, you can commit working code at each (self-defined) milestone. If your code breaks after the last commit, you just need to look at the changes since then. And if you discover the bug after you commit the broken code, you can use git-bisect to find the commit that introduced the bug.
I have put a minimal example project that reproduces the described problem in my GitHub repository. The project is a much simpler version of the project I originally used to debug the problem. It contains only a single XAML file and the error occurs when the application is started, but it is enough to see how the error manifests.
When troubleshooting an application, always read all the information you have and try to fully understand it or interpret it using web search. Use this information to determine possible causes for the error. From there, you can use techniques like the bisection method to further narrow down the options until you find the error. If the permanent fix requires a significant effort, first try to confirm that you have correctly identified the error, for example, by removing the problematic code.