
It took 7 months, but today I finished coding my 2024 .NETpad modernization project. I also found another bug in WPF Windows 7 theming support. Of course I did.
So let’s start there.
When Microsoft released .NET 9 in November, I was surprised to discover that it included a few small but important updates. Key among them was the ability to switch the app theme on the fly, a basic feature that was missing from the Windows 11 theming capabilities Microsoft had previously made available to developers during the .NET 9 pre-release development period. Until that change, you could make an app that conformed to whatever theme the user chose in Windows 11 Settings, and it would change on the fly if the user changed that theme. But there was no way to manually select a theme. For example, if the system theme is set to Dark but you (or the user) want to use the app in Light mode.
Most modern Windows 11 apps support this feature. So, too, does Notepad. And I was sure that it would come to WPF at some point. In fact, I was so sure that I wrote the UI code for this interface in XAML, but left it grayed out since there was no way to change it on the fly. Here’s how it looks.

As I wrote in Modernizing .NETpad: .NET 9 Arrives with a Few (More) Small Improvements for WPF (Premium), Microsoft implemented this capability using a new Application.ThemeMode property in the styling API. And it’s quite easy to use: I spun up a quick sample project in Visual Studio and created a button that toggled between Light, Dark, and System themes (the latter of which will be either Light or Dark, depending on what the user configures). Couldn’t be easier.
But when I added this code to .NETpad and tried to change the app theme, it would crash with an unhandled exception. I have multiple versions of the app, each a little different, so I tried it in three of them. But I always had the same issue. Whenever I changed the theme on-the-fly, the app crashed. Fantastic.
Because I was winding down this project, I decided to not worry about it: I would add this feature early in a clean, new version of the app and then, once I had it working, I’d build it out and keep checking on this toggle to see when (or whether) it started crashing so I could hopefully isolate the problem. I wrote about this a bit in Modernizing .NETpad: WTF, WPF (Premium), in which I also discussed another small but important addition to the Windows 11 theming support in WPF in .NET 9, the new accent color support for the default button in dialogs. That feature, at least, seems to work fine, and I’ve implemented it in all the recent versions of the app I’ve worked up.

But then I got side-tracked a bit. Experimenting on the side, I started getting the long-awaited tab support (and related window title bar customization) working. And so I started to think about, and then implement, the code that would be necessary to transition .NETpad from supporting a single document to one that supports multiple tabs, each with its own document. I first discussed this in .NETpad 2025: Looking Ahead, Feeling a Little Tabby (Premium). And then, I decided to make the underlying changes to the current version of the app I’m working on to better prepare it for the addition of tabs in 2025. I wrote about that work last week in Modernizing .NETpad: Late Breaking Structural Changes (Premium).
Tied to this, I had a basic version of the newly restructured app with a single tab. But then I decided to lose the tab and go with a more traditional looking UI, albeit one with the tabbed-based code underpinnings and a custom window title bar area. So it features the same restructuring as discussed on that last article, but looks the same as before, with no tabs. Once I had that up and running, I started to add back functionality. And I very quickly got to the settings interface. And in implementing the new app theming capability, I had the same issue as before. It kept crashing.
Crap.
So I tested it again and again. What I found was that app theming worked fine … as long as I didn’t do it from the settings interface. If I had clicked a menu item in the main app view, or added a special button, or whatever, it always worked. But every time I tried to change the theme from settings, it would crash. There was something about settings that triggered the problem. This was worrisome as I’m pretty proud of how good that looks, and how much it resembles the similar interface in Notepad. But then I got it to work from settings, too. Just not from within the App theme expander control you can see in the screenshot above.
Finally, I Googled the error (“Value cannot be null”). And what I discovered was that I’m not the only person seeing this issue. In fact, there is an bug in .NET 9 that causes an application crash whenever you make this change while an Expander control is expanded. Microsoft was alerted of this in mid-November, tested a fix, and marked the issue as fixed. But it’s not fixed. If you’re using the shipping version of .NET 9, the bug still triggers an app crash. I guess the fix is in some interim .NET 9 build that will hit stable someday soon. I spent the better part of a day trying to figure out how to make it work, and I finally left a comment about this but have yet to get a reply from anyone.
So, it will work. Someday. Soon, I hope.
Seeing that, I kept working on the app. And today, I finally finished that work. And so I revisited the app theme toggle, saw that it was still crashing the app (as it would), and had to make a decision. I could remove the UI from settings, or leave it grayed out. I could change the UI so that it’s not implemented as an Expander, though the issue there is that the user could expand another Expander on that page, try to change the theme, and still trigger the crash. Or … I could do something else.
For now, I’m leaving it as-is because I feel like Microsoft will issue this fix in stable soon. (The holidays are probably getting in the way.) I thought about adding a menu item, or a set of menu items, for making this change. But in the end, I just added a “Theme” button to the top of the app, to the left of the “Settings” button. You click it to toggle between System, Light, and Dark themes on the fly. And then that setting is saved as per the other app settings. (I had previously added code for app settings to LoadSettings() and SaveSettings() to handle this.)

I should probably have kept notes while I did this, but the latest version of .NETpad features the underlying code changes that will make implementing tabs a little bit easier this coming year, a few fixes for logic bugs that were bothering me (related to Auto save/Timer, document Save as/Save, and a few other things), and some fit and finish work. And I removed the app scaling feature, which seems increasingly unnecessary and had been on my mind. There’s always more to do, and I did make a short list of things I will try to fix/change next year (for example, if you type a keyboard shortcut while viewing settings, you can trigger document actions, like Ctrl + O to open a new document). But it’s time to move on.
Before I post this to GitHub, I will create yet another version of the app, but this will be more of a copy and paste job than me recreating it from scratch in chunks, so it will go faster. The current “master” version of the app has a horrible namespace (CustomTitlebar2) because of the work that preceded it, so I’ll start with a normal “DotNetPad”-type namespace. Once that’s up and running, I’ll do one more pass through all the code to hopefully locate any remaining issues. And then I’ll get the code base up on GitHub so anyone who wants to mess around with it–and, hopefully, recommend any changes–can do so.
Then, I can take a break. And then move on to the next phase of this project and implement tabs, hopefully. I feel like it’s going to go OK within the confines of the ever-present WPF theme issues. But we’ll see.
With technology shaping our everyday lives, how could we not dig deeper?
Thurrott Premium delivers an honest and thorough perspective about the technologies we use and rely on everyday. Discover deeper content as a Premium member.