
Clairvoyance has helped me fix bugs in my app and add new features, but it’s also helped with my imposter syndrome. I’m not a professional developer and I suffer from crippling self-doubt, and so I often assume that the issues I encounter are my fault. But I discovered something reassuring when I reviewed the code that Clairvoyance had created to handle multiple documents and tabs in WinUIpad: Much of the code and architectural design it used was my own.
If you go back and review the articles I wrote a year or more ago about implementing multiple documents and tabs in the WPF version of this app, called .NETpad, you will find that I first started working on the underlying architecture for this work in late 2024. I created a C# class called DocumentTab to handle per-document state, meaning data like the document’s name, whether it’s saved, whether its contents has changed, and so on. DocumentTab evolved over time, of course, but I had the basics down about a year and a half ago.
My goal for this app in 2025 was to implement the multiple document/tab functionality. But that didn’t happen, in part because of limitations in WPF—most notably, its tab controls were designed for the tabbed dialogs of the early 2000s, and not for multiple document apps like mine—and in part because I then decided to migrate over to the more modern (but terrible) Windows App SDK and WinUI 3. And that required significant effort, research, and learning. Still does.
What I ended 2025 with was frustration. Yes, the Windows App SDK and WinUI 3 let you make a modern looking app, thanks to the native support for Windows 11 controls and styles. But the Windows App SDK also lacks many of the features my app needs that are supplied by WPF. And so I kept finding myself stumbling over the basics, having problems with things I had solved in other frameworks a long time ago. It was one step forward, one step back.
Fundamentally, I had to tie each document to a tab and ensure those two things stayed in sync, and I somehow had to do this using a framework, the Windows App SDK, which seemed uniquely unable to properly handle basic events like what happens when the user switches tabs. So I was curious to see whether Clairvoyance could solve this problem. And then when I saw that it had, I was curious how it had solved this problem.
Think about Notepad in Windows 11 and the interaction between the tabs at the top of the app and the text box at its center. Each tab is associated with text in the text box, but those tabs are also separated from the text box with a menu bar.

In the Windows App SDK, the TabView control is a container: It contains tabs (TabView controls), of course, but also other items like a header, which can include an icon as per Notepad (and WinUIpad), and a footer with the “Add new tab” button. But each TabView control is also a container: It can contain an icon, some content (typically text), and a “Close tab” button in its header (what most think of as “the tab”), and a big content area below it.
Ideally, the tab (header) and document in the text box (content) would be visually connected because this simplifies the implementation. You can create each tab and its contents in XAML, C#, or some combination of both in a straightforward manner. But in Notepad, that menu bar is in the way. How might we solve this problem?
My ape brain considered two solutions to this problem:
Create a unique menu bar for every document and tab. In this design, I would dynamically create a tab that contained a complete menu system and a text box to ensure that the tab (header/container) and document (text box/contents) would be part of a single object, eliminating the need to keep the two in sync. The downside was a lot of unnecessary recreation of the same menu system every time the user created a new tab.
Create a single menu bar and text for the entire app. In this design, I would simply create one menu system and one text box and reuse them for each document. When the user switched tabs, I would save the state of the now-previous document and then load the state of the correct document, populating the text box and positioning the cursor (and handling whatever other state) correctly. This seemed like the best approach to me, and it would work well with WPF. But this is where the Windows App SDK’s different handling of events got in the way.
If you followed along as I made .NETpad and WinUIpad, and you have a really good memory for tedious information, you may know that I implemented both approaches to some degree. But Clairvoyance opened my eyes to a third approach, an approach that works well with the Windows App SDK. And, perhaps, more importantly, it is just a better solution overall. It’s something that never occurred to me.
As with my two approaches, the Clairvoyance solution creates an empty TabView in XAML and then creates each TabItem (tab) dynamically in C#. It then creates a single menu system, in XAML, for the app. So far, so good.
But then Clairvoyance did something I never considered. It creates a single empty Grid container, in XAML, where the text box will go. Then, when it creates a new tab dynamically in C#, it also creates a new text box dynamically in C# too. Both are linked so that the correct tab header, document contents/TextBox control, and other state information appear as the user changes, creates, and closes tabs.
I already knew that this design worked because the app runs fine. But seeing the code, I immediately understood why it worked, and I was vaguely unhappy with myself for not ever coming up with a similar design. I guess you could argue that it’s a hybrid of my two designs, sort of. But it’s difficult for me to not see this as personal failure of sorts.
With this eye-opening experience behind me, I decided to restart the WinUIpad project yet again. I started with the basic user interface, or UI layout, building this new version using my previous WinUIpad version and the Clairvoyance version as references, each in its own instance of Visual Studio. At the conclusion of the previous article, I had just the basics done, with a single tab and document, but no way to add or close tabs, do file operations, and and whatever else.
Since then, I have made a lot of progress. Right now, I feel better about this app than I have in, oh, two years, I bet.
This happened quickly, which makes sense since all the code I need is out there between the two other versions, and I didn’t take good notes. But long story short, I’ve done the following:
The Clairvoyance-created app is technically very good to excellent, from what I can tell, but the overall look and feel of the app is lackluster. It put the Settings (gear) icon in the wrong place, didn’t properly style the active or inactive tabs, and other visual glitches.

But XAML is one thing I’m pretty good at now. And so I implemented a lot of changes to the app user interface after first building it out to mimic my original style. The active tab and menu bar are now styled identically so that the former flows correctly into the latter. And the Settings (gear) button is in the right place, to the right of the menu bar.

I also went further with the design after reconsidering a few previous choices I had made. I removed the curved corners on the TextBox(es) so that it/they now extend cleanly to the edges of the app. And I made the menu bar less tall, and more like that in Notepad.
Last time, I had just a single File menu item as a placeholder of sorts. But in preparation for (re)implementing file operations and all the event handlers associated with each menu item, I decided to just build it out in XAML, with empty (for now) event handlers for each in C#.
The menu system in my version of WinUIpad closely followed the design of that in Notepad, with top-level File, Edit, and View items. But the Clairvoyance version added a Format top-level menu item, moved some menu items around, and added some new ones, like those for the new line ending and encoding features it added. I’m not sure those options belong in a menu, but for now, I just created something very close to my version of the menu system.

That said, I did add items for line endings and encoding under the View menu. And I added a Settings item there too.

This will be refined further as I build out each event handler and consider the design more.
Similarly to above, I blocked out the status bar items as per the Clairvoyance design, which is based on my design but with additional items for line ending and encoding formats. These don’t do anything yet, but that will come.

From there, I moved on to the code that runs when a new tab needs to be created, as when the app starts or when the user does so via the “Add new tab” button or the File > New tab item. This occurs via the CreateTab() method.

With this done, I could open a new tab manually, type text into each, and see that the document contents were anchored to the correct tab when I switched between them. So I implemented Close tab next, which happens via a CloseTabAsync() method. And that let me ensure each tab retained the correct document contents as I closed tabs.
Typing random text into a TextBox control to test the above functionality gets old quick, and so I moved from there to the File open operation. This is straightforward and is handled directly in the OpenMenu_Click() event handler. And with that done, it became much easier to see how well the tab switching, and thus the document state in its current limited form, works.

None of this is earth-shattering per se, but the app looks great and is handling the difficult parts effortlessly, and so you can perhaps see why I feel so good about it now. There are difficult things still to come, like the session state management stuff I despise (and disable) in Notepad, but that’s all there for the taking, as are the other features that I and Clairvoyance separately implemented.
Put simply, I know this will work.
More soon.
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.