
Inspired by Microsoft’s decision to bring the Windows Presentation Foundation (WPF) back from the dead and support Windows 11 theming, I decided that I would modernize the WPF version of my .NETpad app and try to add the features that Microsoft has added to Notepad. That work went better than expected in 2024, though support for multiple documents and tabs always loomed over my head like a shadow. As 2024 wound to a close, I decided to punt on multiple documents/tabs and save that work for 2025.
I published my updated (non-tabs) version of .NETpad to GitHub in late December. And then I spent the first half of this year steadily building out multiple documents/tabs support in the app. And while I experienced some nice wins, I kept running into the same problems again and again. So I hit reset: I’m now updating the single document version of .NETpad with a more sophisticated codebase and new features to get off the no-progress treadmill.
But I haven’t forgotten about multiple documents and tabs. Indeed, I’m mildly obsessed with it, even though I very much prefer the current, simpler version of .NETpad. And I’ve had this recurring thoughts in the back of my mind this whole time, dating back to last year. Modernizing an existing codebase is a pretty common activity for developers, which explains why Microsoft resuscitated WPF in the first place: There are so many WPF apps out in the world and making them look right in Windows 11 was previously difficult to impossible. But modernization can only go so far. Sometimes you need to start over.
And in my case, it’s obvious looking at Notepad today that Microsoft used the Windows App SDK and its native support for WinUI 3 to modernize the app. It’s also obvious that WPF isn’t up to the task I’m trying to accomplish. As I noted in the reset article, its TabControl and TabItem controls are literally 25 years old and don’t address the modern needs of tabs-based apps like the one I’m trying to build. Working around that isn’t literally impossible. But it is incredibly difficult and the result will never be ideal. I always figured there was a Windows App SDK/WinUI 3 version of .NETpad out there, just waiting for me top write it. What if that was the solution?
All I had to do was find out. And sure enough, a cursory look at the documentation told me exactly what I needed to know. Among other things, it verified what I’ve been saying all along about the tabs capabilities in WPF.
“Tabbed UIs come in one of two distinct styles that differ in function and appearance,” the Microsoft Learn documentation for the WinUI 3 TabView control explains. “Static tabs are the sort of tabs often found in settings windows. They contain a set number of pages in a fixed order that usually contain predefined content. Document tabs are the sort of tabs found in a browser, such as Microsoft Edge. Users can create, remove, and rearrange tabs; move tabs between windows; and change the content of tabs.”
Two things to that. Static tabs are what WPF was designed for over decades ago. And document tabs–Microsoft literally uses the same name I used for my custom DocumentTabs class–are used for apps like Notepad and, if I can get this done, .NETpad. The tab controls in the Windows App SDK and WinUI 3–called TabView and TabViewItem, respectively–are what I’ve wanted, what I’ve needed, all along.
But it gets better. The TabView control includes features I had to manually try to create myself in WPF, like the area for the app icon to the left of the tabs, the “Add tab” button, and the space to the right of the tabs. It’s all there. It even has things I couldn’t do, like automatic tab management with overflow, tab rearranging with drag and drop, and even drag and drop between windows.
Oh my.
With the understanding that everything I just described is user interface, not code, so it doesn’t solve the event handling issues I keep experiencing in WPF, I began to experiment. I was curious about the basic features noted above. Whether they worked at all in basic XAML. Whether I could use them in more sophisticated ways, perhaps via one or more UserControl controls, to reuse code efficiently. Whether this in any way made any sense at all.
There are still so many open questions, but what I found so far is mostly quite positive.
From a basic XAML perspective, WinUI 3–I’ll just call it that for simplicity’s sake now–solves my problems. I can use the WinUI 3 TabView and TavViewItem controls to create a pixel-perfect duplicate of the Notepad user interface. That makes sense, as the Notepad user interface was made with WinUI 3. And it gives me so much, as noted above. The tab overflow user interface (and related functionality) alone is a huge step forward.
Here, for example, you can see the basic app with an app icon to the left of the first tab, a single tab with a “Close tab” button, and an “Add new tab” button, all of which are just built-in.

As I add tabs, there’s a nice little divider line between each. And if I add enough tabs, the overflow interface we see in Notepad appears. It just works.

I was able to implement tab close and tab drag and drop very quickly. And it’s easier–not “easy,” but easier, and it’s apparently going to improve again soon–to customize the title bar area of the app than is the case with WPF. As you can see, I don’t lose the Snap suggestions as with WPF.

Less obviously, each TabViewItem–each tab, in other words–has header and content sections, as is the case with WPF TabItems. And while there are all kinds of ways to handle this, I’ve decided that recreating the same menu bar system and text box for each tab is the way to go because it will help with state management, my most vexing issue. So I built that out first in XAML, and then as a UserControl, and then as raw C#, and then, finally, as a bit of C# that created a new TabItem, added the header in code, and then inserted a pre-built UserControl, which I implemented in XAML. All of this worked just fine.

But this is where things get tricky. I have to programmatically access controls in the main window from the UserControl, which is another class with visibility and accessibility boundaries. And I have to do the reverse. And I have to figure out how to differentiate all the different tabs–which are a mix of C# and XAML code, each with a UserControl–from each other. In other words, I have to manage state. Some of this is automatic, which is nice. When you switch from tab to tab, there’s no work required to display the correct document. But some is not. It’s still work.
And that I have not figured out. Not because I can’t, but because I’ve just started working on it. And it’s not the only thing I’m working on, in this project and otherwise. I’m just taking the first steps here.
For now, I want to continue to experiment with the best ways to do what I need to do. It has to work consistently, of course. I’d like it to be as “correct” as possible, from a code quality/best practices perspective. Ideally, there would be data binding. Maybe a formal MVVM design pattern. I don’t know. I’m still working through things.
There’s also the possibility of putting a WinUI 3 front-end on the existing WPF app. I believe this is technically possible. It’s what Microsoft did with Notepad and Paint in Windows 11, though the backend/original apps are C/C++ Win32, not WPF/.NET. But that’s one of the rationales for the Windows App SDK: You can use it to modernize an existing app. Perhaps I don’t need to completely rewrite it.
Perhaps. I probably should, regardless. But I will continue researching that as well. No rest for the wicked and whatnot.
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.