
There is an alternative timeline in which I became a software developer. It’s what I went back to school for in the early 1990s, and it’s what I was doing when life took me in a completely different direction. But as I noted to my wife this morning, if there’s a job out there that’s even more frustrating than what I do today, it’s being a software developer. And as a proof point for this opinion, I will offer up this story. Which is my second major example of this happening since I decided to modernize .NETpad in May 2024.
I feel like I spend half my time in articles like this getting everyone up to speed on what’s happened before this point. But this time I will be brief.
I restarted .NETpad using the Windows App SDK (WASDK) and WinUI 3 because this is the only way to deliver a modern version of the app with elegant support for multiple documents/tabs and other features I want to add.
As a “native” Windows app framework, WASDK/WinUI 3 has similarities with the Windows Presentation Foundation (WPF) that I was using previously, including its use of C#, .NET, and XAML, and general similarities between the frameworks. But they’re also painfully different in ways both big and small, and all across the frameworks.
That’s to be expected, on some level. But I’ve been surprised to discover that WASDK/WinUI 3 also have some unique problems. These include literal functional regressions when compared to WPF, meaning features that are present in WPF but are not available, in any form, in WASDK/WinUI 3. And also some odd instances in which these issues are known to Microsoft but never fixed.
This is an example.
Look, I try to roll with the changes as much as the next guy. When WASDK/WinUI 3 doesn’t offer a StatusBar control like WPF and every other Windows app framework dating back to Adam and Eve, I can handle that. I can just use a Grid and add TextBlock controls. No problem. When I discover that WASDK/WinUI 3 supports Light and Dark mode themes explicitly but does not understand “Use the system theme,” I don’t like it, and it doesn’t make sense, but I can handle that too. There are numerous small things like this.
But there are bigger issues, too. I alluded to one in the previous version of the app when I wrote that commanding in WASDK/WinUI 3 was “so freaking different” from how this works in WPF that I would need time to figure it out. But since then, I began to understand that it may not work at all, and that I will probably need to do something completely different.
I will figure that one out. But this is a different issue. Related, I guess. But a good example of how WASDK/WinUI 3 can really bite you in the ass in ways you just don’t expect. Because they make zero sense.
A lot of the work I’m doing now is basic, meaning it’s functionality I figured out several years ago, first in Visual Basic .NET and Windows Forms, and then in C# and Windows Forms, and then in WPF, and then in UWP, briefly, before returning to WPF. You draw the app user interface, you wire up the event handlers, you make an app. This app has a menu, a settings interface, and dozens of commands–let’s call them features–that are all familiar, things like File save, New document, Find and replace, and whatever else.
Microsoft frameworks have changed over the years. But over the course of several years and different frameworks, .NETpad has basically always been a single window app with an UI created in XAML and wired together on the backend with C#. As I moved towards adding multiple documents/tabs support, however, I realized that it would need to be more sophisticated, and so I’ve experimented with more elegant architectures that can be more easily maintained and updated over time. There’s a lot that goes into that, but one of the bigger pushes I’ve made is to use data-binding to automate the interaction between what the user sees and does on-screen and what happens on the back-end. That is, instead of manually updating properties and values in response to events–a text change in the app’s text box, a configuration change, or whatever–I can (ostensibly) write less code and let data binding do this work for me.
Yes, this is about data binding.
I started working with data binding when I was still using WPF. And in the transition to WASDK/WinUI 3, I thought that this was one area in which the two frameworks were consistent, if not completely identical. And so that was among the easier shifts for me up front.
Until it wasn’t.
Look, I’m not sure how other people work. And I’m absolutely not sure how real developers work. But I follow pretty consistent patterns, and I have specific ways of doing things. When I run into a problem, I use the debugging tools in Visual Studio and my own stupid little cheats to try and solve it. And I’ve been using GitHub Copilot in Visual Studio, AIs like Perplexity, and Google Search, which has AI-based summaries in its results now, as needed. This has been a Godsend for the most part, especially for something complex like data binding. But they all failed me to some degree here. Not because they’re incapable. But because WASDK/WinUI 3 is broken. In this case, in a weird, small way.
I built the basic interface for WinUIpad, the WASDK/WinUI 3 version of .NETpad, in XAML, as before. But then I redid most of it–the code for each tab (which is a TabViewItem that contains a header and then a content area with a menu system, a text box, and a grid for the status bar)–dynamically in C# so that it could be created on the fly, important in the future when it has multiple tabs. For this work, AI was indispensable.
Then I worked on the basic file management functions, things like New, Open, Save and Save as. That took a bit of work because of all the small differences. But it’s there now.
Then, I create the settings page from scratch. I used XAML, as I did with the WPF version of the app, and though I re-did it completely and never used any of my previous code, it’s just about identical. But whatever. It’s there, and after experimenting with different ways to show/hide settings, I ended up using a technique that’s nearly identical to the WPF version of the app. This was, if anything, even simpler than was the case with WPF.
I mentioned that I’m still trying to figure out how or even if commanding works in WASDK/WinUI 3. And I’ve spent time on that. But I also wanted to use data binding as much as possible. And so I’ve spent a lot of time on that. A lot of time.
And I’ve run into all kinds of issues. Sometimes data binding works, sometimes it doesn’t. Data binding is difficult to troubleshoot, and while you can use a “Binding failures” view in Visual Studio to discover some binding problems, it only works for one of the two types of data binding syntax you can use in WASDK/WinUI 3. I want to use the more modern version, which “Binding failures” doesn’t support. And so I have to really test these things manually.
So I break it down. I create a new Visual Studio side project that’s a small subset of the full app so I can test. this case, what I wanted to do was bind two properties in my AppSettings class, WordWrap and StatusBar, to whatever user interface elements interact with them. This could not be simpler. Both are boolean, meaning their state is either true or false. And both interact with only a limited number of UI elements.
StatusBar is the simplest of all. It can be true or false. If it’s true, the app’s status bar (which is now a Grid with TextBlocks controls) displays. If it’s false, the status bar is hidden. And there are only two controls that relate to StatusBar: The MenuItemFlyout in the menu at View > Status bar and a ToggleSwitch control in the settings UI. So if you’re using the app and you select View > Status bar from the menu while the status bar is displaying, the following should happen:
Easy, right? Actually, yes. This is straightforward to do with raw code. But it’s also straightforward to do with data binding, once you get up to speed on all the weird boilerplate code you need for any data binding. This is an example of something that I got working pretty quickly.
The first data binding side project I created handles WordWrap and StatusBar. I had used it previously to figure out the combo boxes needed for the Font family, style, and size interfaces in the settings page. And then I moved on to the next settings, for Word wrap and Status bar, which is when I ran into my first big data binding issue. In any event, this simple app uses copy/pasted code from the main WinUIpad app that displays the toggle switches for these two features, a TextBox, and a Grid-based status bar.

The Status bar bit works great. When the StatusBar property in the AppSettings class is set to true, the Status bar toggle switch near the top of the app is set to “On” and the actual status bar is visible. But when you switch the toggle switch to “Off,” the status bar disappears (collapses). Perfect.

Naturally, I reused this code for Word wrap. But Word wrap has a unique problem.
In this sample app, Word wrap works like Status bar. It’s a toggle. It’s either true or false, meaning on or off. But when I clicked the Word wrap toggle switch, changing it to “Off,” the TextBox control didn’t change. TextBox has a TextWrapping property that toggles Word wrap on and off. But TextWrapping is not a boolean. It’s of type TextWrapping. And it can be set to “Wrap” or “NoWrap”.
These things should just map automatically, right? If the WordWrap property in the AppSettings class is set to true, TextBox1.TextWrapping should automatically change to Wrap. And if it’s false, TextBox1.TextWrapping should be NoWrap. But that’s not how this works. WASDK/WinUI 3 cannot automatically cast a boolean to a TextWrapping.
Data binding supports Converters that you can use or create to handle these issues. Only some are built-in, however, so most of the time you have to create them yourself. This is silly: As with TextWrapping, there are dozens if not hundreds of instances in this framework in which some random collection value is used for whatever control properties, and they should all auto-convert from boolean. But they don’t.
OK, fine. I mentioned above that I can get by these little stumbling blocks. Here’s what I tried.
My first side app related to data binding and WinUIpad was a bit too busy. In addition to working with two properties and their related UI controls, there were other things going on there related to my testing that aren’t worth discussing. Long story short, I made a second side app experiment. This one just for Word wrap and even simpler.

This app has a menu with a File > Word wrap item, a toggle switch, a text box, and a Grid-based status bar with a two text blocks. The menu item, the toggle switch, and the second text block were all data-bound to the WordWrap property in AppSettings. The point there is that if you change the Word wrap setting using the menu or the toggle switch, all the relevant UIs will change: The menu item is checked when Word wrap is enabled (i.e. WordWrap is true), the toggle switch will be “On” or “Off”, and the text block will display “True” or “False.”

All that works great.
But the trick here, and this is obviously essential, is that the text box should wrap or not wrap its text accordingly as well. And that’s the bit I couldn’t get working. To make sense of this, I will need to show you some code.
To use data binding, the data source–in this case, my AppSettings class–has to support the INotifyPropertyChanged interface. And then each property you use has to be defined correctly with a setter and getter. This is where all the boilerplate code comes into play. You also need to implement an OnPropertyChanged event handler at the class level and … whatever. For just a single class with a single property, the minimum amount of code is basically this:

Yes. Ugly. But you can reuse this for subsequent properties and it gets easier.
You can bind this property (the data source) to the property of a control (the target) in XAML or C#. I’ve done both, and will need to do both, depending on the instance. But for the first pass here, it was all XAML, which is probably easier to read. There are four places where I needed to add binding code. And the first three were all straightforward:
The code for the first two is identical because the user interacts with them. So the binding has to be two-way. For example:

For the TextBlock, the only difference is that the Mode is OneWay: The TextBlock only displays the value, and because C# can convert from boolean to a string automatically, this just works.
The problem is the fourth place I need to add binding code, the TextWrapping property for the TextBox control. If I use the same code as above, it fails. The issue? It can’t convert from boolean to TextWrapping. So I had to create a converter. Which I did.
This requires a lot of extraneous code, too. Each converter is its own class and each has to support a Convert method and, optionally, a ConvertBack method. Each converter has to be referenced, in XAML, in a resource dictionary, and that resource dictionary must be linked to the project in App.xaml. And some other minor additions.
But I forged ahead. I created the converter class, which I called BoolToTextWrappingConverter. It has a Convert method that, yes, could be simplified/condensed, but I’m looking for clarity as I test. (It doesn’t have a ConvertBack method because it’s not needed: This is a one-way binding, and there’s no way for the user to change this from within the text box.)

I added a resource dictionary in which I create an instance of this class with the same name for simplicity’s sake.

And then I added the binding code to the textbox in the XAML.

Yeah, it doesn’t work. It should work. All the AIs I tried think this should work too. And they’re right. Which I know now, after a few weeks of failing.
You may recall that when I initially modernized the WPF version of .NETpad last year, I ran into an issue in which my UI for changing the app theme could crash the app when used. I struggled with that problem for months until I finally discovered it was a bug in WPF that Microsoft knew about, fixed internally, but didn’t deliver to the public until months later, at which point my code just worked. This was infuriating on several levels, including me reaching out to the person directly responsible for the bug and not ever hearing back until well after the public fix.
But the bigger issue there is tied to me not being a professional developer and not trusting myself. I assumed Microsoft knew what it was doing. That this was my fault. And that the solution was me fixing something I had done wrong.
Well, it happened again.
That data binding code I wrote, including the converter, should work just fine. In fact, it will work … in WPF. But there’s a bug in WASDK/WinUI 3 that’s been known for at least four years and is still an open issue. You can’t use x:Bind, which is the newer and more efficient data binding syntax, with a converter.
No problem. I can adapt: You can use the older data binding syntax, Binding, with a converter. This is what’s in the previous shot, above. This version doesn’t error out. But it also doesn’t work. It does … nothing.
And this, too, is a bug in WASDK/WinUI 3 that’s described in that GitHub post referenced above. The issue is that binding with a converter won’t work if the root of the XAML file is a Window. Which is how most apps are made. This works fine in WPF (and, I’m told, in UWP and MAUI). But not in WASDK/WinUI 3.
Microsoft knows this. It explains why to the confusion of everyone, as any sane developer would simply tell them it should work, it has always worked, and your own documentation says it works. But it does not work.
Microsoft has workaround recommendations. You can hollow out your MainWindow.xaml code so that it’s just near empty shell and then put the code for the app UI in a Page or UserControl, both of which are supposed to work. (I haven’t gotten the Page-based approach to work, and I’m trying to avoid UserControl.)
But the main point here is, it’s not me. With a side helping of, I just wasted weeks on this. On f#$%ing Word wrap. For frick’s sake, Microsoft.
Well, I can adapt to this, of course. And no, it’s not going to be with a UserControl or a Page. I will just handle this instance in which the user actually configures Word wrap manually for the TextBox. I’ll use data binding elsewhere, wherever and whenever I can. But with Word wrap–and, I’m sure, in other places I have yet to run into–I will also manually change the value of TextBox1.TextWrapping. You know, just like we used to do in the 1990s.
I knew going into this that there would be challenges and setbacks. But this is silly. It’s such a basic app feature. And it’s disappointing to know how terrible this situation is. This is why Microsoft had to announce that, yes, it was still serious about the Windows App SDK and it will try to do better going forward: There are all these unresolves issues out there, never fixed, long forgotten, and ignored. And developers are right to be upset about that. It’s unprofessional. It’s unfathomable. But it’s the reality for those hardy few who, for whatever reasons, still want to make native Windows desktop apps.
I feel for you all.
More soon. I hope.
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.