WinUIpad: Fixing Problems with AI ⭐

WinUIpad: Fixing Problems with AI

This past weekend, I described my early experiences using Stardock’s Clairvoyance as a frontend to Anthropic Claude Pro to see whether I could use them together as an AI pair programming solution to help me get WinUIpad back on track. I had had mixed success doing this with GitHub Copilot in Visual Studio, and with Claude. But I went into this experience with high hopes, mostly because Brad had given me a few live demos and what I saw was impressive.

What I found exceeded my expectations, and that opened up a new possibility: In addition to fixing the current, single document version of WinUIpad, I secretly hoped that I could use this set of tools to finally implement what I’ve called my version of Ahab’s white whale: The multi-document, multi-tab version of WinUIpad that was the original point of this project. With apologies for the vagueness, I can now tell you that it will happen. Indeed, it has already happened.

But first things first.

Code review

If you’ve ever had to walk into a boss’s office and sit through an annual assessment, you understand how terrifying it can be to have someone else judge you and the work you do. Getting a review of code you wrote is pretty much identical. It’s not for the overly sensitive.

I’ve told this story before, but when I started writing books in the early 1990s, I had the horrible experience of my co-author, a professor and a genius, reviewing the code I had written for what became a book about Visual Basic 3.0, and finding it lacking. “Are you sure about this?” he asked once while reading a paper printout of some code. “I was,” I replied. Knowing that he had found an error because he was smarter than me and knew far more about programming and this language in particular.

If you want to experience this for yourself in the 21st century, you can ask an AI, pretty much any AI, to review some code you wrote. I’ve done this at least a few times, perhaps most notably with Cursor back in early 2025 when that was a unique bit of functionality that it provided. And regardless of which AI I’ve used, I’ve noted two similarities. It’s always useful and AI tends to be perhaps overly complimentary, so this process isn’t as painful if you’re sensitive to criticism.

Given all this, the first thing I asked Clairvoyance to do—and, yes, this is really Clairvoyance plus Claude Pro, but let’s just call it Clairvoyance since it can work with any AI backend—was to provide me with a code review of my WinUIpad project. To do so, I created a new Workspace in Clairvoyance and pointed it at the WinUIpad project folder. Then, I typed the following prompt:

can you examine the source code of this windows app sdk project and tell me about any issues you find

That simple.

Clairvoyance examined the contents of the folder, got acquainted with the structure and contents of its source code files and, within half a minute or so it spit out a detailed report that was separated into three sections: Bugs, Code quality/warnings, and Already-noted To-do’s that were based on the comments I had placed in the source code myself. It then added an interesting summary with some ideas for next steps.

“The most pressing ones to fix are probably #1 (race condition on Open), #3 (filename overwrite on cancel), and #4 (silent data loss on failed save),” it concluded. “The rest are mostly correctness/polish issues. Want me to take a crack at any of these?”

Why yes. Yes I did.

A quick note before we dive into this. I’d created a basic, functioning version of the app that supported a single document. It mostly worked, but at some point a few months back I stripped out all the non-working bits, UI and backend code, to further simplify it and to get a better idea of where it was at. My goal, moving forward, was to tackle individual features/additions, one at a time, and to use whatever AI and/or traditional Google Search approaches, knowing that in doing so I would often have to explain some context in the process. Using an AI like this, where it understands the entire context of a project going in, is a nice step forward. It’s a convenience, on some level, but it’s also more than that. It’s what an AI pair programming solution is supposed to do, be a partner that can help you along the way.

I needed the help.

Fixing the big problems

Clairvoyance had identified 7 bugs, three of which it felt were serious. So I obviously wanted to start with those.

The first was a race condition in my File > Open menu’s Click event handler. Or, as Clairvoyance put it:

1. Race condition in FileOpMenu_Click (Open) — MainWindow.xaml.cs:293. OpenFile is declared async void, so it can’t be awaited. The UpdatePosition() and UpdateRecentFilesMenu() calls on lines 294–295 fire immediately, before the file is actually opened.”

I won’t beat all of these to death like this, but since this is the first serious bug it found, it may be worth a brief look. MainWindow.xaml.cs is the main C# “code behind” source code file. FileOpMenu_Click() is the event handler for File Open and File New because there was so much redundant code when they were separate. There’s a switch statement that determines if this is a File New or File Open operation and, if it’s the latter, it tries to open the file the user selects and then it calls two of the helper functions that I wrote, UpdatePosition(), which is for the Ln/Col display in the status bar, and UpdateRecentFilesMenu(), which is for a Recent Files menu I had yet to implement.

The way I wrote this, the File Operations OpenFile method—fo.OpenFile(this, doc) in the code—wasn’t happening asynchronously. So those two methods would fire before that method completed. Bad, Paul. Bad.

So when Clairvoyance asked me whether I wanted it to take a crack at any of the bugs and other issues it had found, I wrote:

Yes. Start with the race condition

This fix took about 10 seconds, perhaps. As did most of the subsequent fixes. Clairvoyance churned a bit and then came back with:

The fix is two parts: change OpenFile from async void to async Task, then await it at the call site.

That’s it. UpdatePosition() and UpdateRecentFilesMenu() will now wait for the file picker and file read to complete before running.

Two document icons indicated that it had changed two source code files.

In FileOperations.cs, it changed the beginning of the OpenFile() method from this:

public async void OpenFile(MainWindow mw, Document d)

to this:

public async Task OpenFile(MainWindow mw, Document d)

And in MainWindow.xaml.cs, it changed this line of code:

fo.OpenFile(this, doc);

to this:

await fo.OpenFile(this, doc);

This is not particularly complicated, indeed it feels obvious and like something that I should have never screwed up. But Clairvoyance had come back so quickly, it was disarming. I switched over to Visual Studio, where I had the project loaded but none of the files open in the editor, and I checked the two files it had changed. Everything looked fine, so I clicked the “Start debugging” (F5) button in Visual Studio to rebuild and run the app. It worked fine.

So I started stepping through the other big bugs. This went quickly.

Clairvoyance asked:

Ready to move on to #2 or #3?

Bug #2 had been described like so:

2. Dead code in BeforeClosing() — MainWindow.xaml.cs:239. Inside the else branch (which only runs when appWindow == null), there’s an immediate if (appWindow != null) check. That block can never execute.”

Doy. So I replied with:

Yes, let’s fix #2, the dead code in BeforeClosing()

And sure enough, within several seconds, Clairvoyance came back with:

Done. The unreachable if (appWindow != null) block inside the else branch is gone. On to #3?

After reviewing the code as before and rerunning the app, I gave in to the inevitable and replied with:

yes please

Again, several seconds passed. And then it responded:

Gone. The redundant block was setting d.FileName to a value already assigned inside the if block above it, and clobbering the previous document’s filename with “Untitled.txt” whenever the user cancelled the picker. Now if the user cancels, the document state is left untouched.

Seeing this, I realized it had resolved a problem I had seen but had trouble reproducing. So there you go. I checked the code, and then rebuilt and re-ran the app. Everything was fine.

Ready for #4?

Bug #4 was a potential data loss issue. Or, as Clairvoyance had described it:

4. Silent continue when save fails in NeedsToBeSavedAsync — FileOperations.cs:72–76. If the user clicks “Save” and SaveDocument() returns false (save failed), the code breaks out of the switch and falls through to return true — telling the caller to proceed anyway (e.g., close the app). Data loss risk.”

Sigh. Yes. Of course.

yes thanks

Again, just several seconds passed. And then Clairvoyance replied with:

There are two instances — the menu handler and the context menu item. Let me read both to get the exact current state. ? ?

Both cases: replace the Loaded subscription with a direct Focus call, since the TextBox is already loaded at this point. ? ?

Both fixed. The Loaded event never fired anyway since the TextBox was already loaded — now Focus is called directly, and no handlers accumulate.

Those icons indicate source code files that it had edited. And, once again, I reviewed the code, everything was fine, I re-ran the app, and it worked.

And those were all the major bugs. What about some of the other issues?

Fixing the other problems

Clairvoyance had identified three other bugs (one of the fixes above actually fixed two issues) and 6 code quality/warning issues, and it had listed the to-do’s I had already made in the code. With the three biggest bugs fixed, it prompted me to see whether I had wanted to fix bug #6 for some reason. Naturally, I said yes, but the short version is that I used Clairvoyance to do the following:

  • Fix an inconsistent line-ending split (\n vs. \r) in two different methods.
  • Change an instance of synchronous file I/O on the UI thread to be asynchronous, which is what all file I/O operations should be.
  • Remove a double assignment of the file name value.

Each of these took seconds not counting me reviewing the changes and rebuilding the app each time. So Clairvoyance then wrote to me:

That covers all 7 bugs. Want to keep going with the code quality items?

Duh, and/or hello. But this time, it surprised me by just doing it all at once. Here’s what it wrote.

Let me grab the relevant sections for all the remaining code quality items at once. ? ? ? ? ? ? ?

Got everything I need. I’ll fix all remaining code quality items in parallel across the files. ? ? ? ? ?

Now the two cross-file changes — unused App parameter in ResetDocument, and the dead import in FileOperations.cs. ? ? ?

All done. Here’s a summary of what just changed:

8 – Removed spurious async from Font_Configuration() and SettingsButton_Click()

9 – Removed dead loop in Font_Configuration() that was immediately overwritten by the line below it

10 – Removed unused App app parameter from Document.

ResetDocument()and updated both call sites | | 11 | Removed unused`using System.

Reflection.

MetadatafromFileOperations.cs| | 12 | Fixed|||inUpdateCount()| | 13 | Removed the hardcoded +100 offset from the context menu position |

That’s everything from the original list that’s actionable. The remaining items (broken UpdatePosition, multi-window support, save-after-new-document edge case) are the ones you’d already flagged as known TODOs.

And for the love of God, everything was fine.

Frankly, I was quite dazzled by all this. I’ve tried to use AI so many times to resolve problems and I kept running into an issue where the fix it would provide would trigger new problems. But nothing here, not one thing, triggered any issues. Everything worked fine and on the first try. This was … unexpected.

Emboldened by this success, I decided to tackle some functional additions next and see if Clairvoyance could solve a major issue with the app that I had struggled with.

More soon.

Gain unlimited access to Premium articles.

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.

Tagged with

Share post

Thurrott