
I’ve made incredible progress on .NETpad’s support for session state management and multiple documents and tabs. But the code is brutally difficult, and messy in testing. And it’s the type of thing I should only work on with a fresh brain. Foolishly, perhaps, I spent a few hours on it while flying to Mexico on Saturday and did OK, all things considered. But it was late, I was a bit beat up, and I needed a small win.
This is it.
It’s nothing earth-shattering, but it’s on the to-do list. It’s something I had previously changed in one of the several different versions of this project I’m stupidly juggling. And so I didn’t really need to write any new code. All I had to do was clone the .NETpad 3.0 for Windows 11 repository in GitHub to a new Visual Studio project to get a clean version of the code base, add my changes to it, and then push the changes back up to GitHub. Then I could check the item off the to-do list and enjoy 10 seconds of peace. Or something.
That item, as noted in the article headline, is a custom MessageBox dialog. It’s something I should have done months ago and added to the app in its initial release. I have no idea why I didn’t: .NETpad 3.0 includes several nice-looking custom dialogs–for Auto save, Confirmation, Find/replace, and Go to line–and all of them are more complicated than a basic MessageBox. Sometimes you have to just shake your head and not over-think it.
The issue, if you’re not familiar, is the system MessageBox you can access with WPF isn’t styled for Windows 11.

But the MessageBox dialogs that Notepad displays are properly styled for Windows 11.

Not including the MessageBoxes I use to display error messages, there are two major instances in which .NETpad, like Notepad, needs to display this type of window.
In both cases, we just need an error message and an OK button. Simple
My custom MessageBox is called MessageBoxDialog and it’s based on the same basic XAML code I used for the other custom dialogs. This one is as basic as it can be, however, so it’s even simpler. It supports a title, a message, and an OK button. The title and message are both TextBlock controls.

There are only three event handlers.
The first one is the constructor, which runs when code elsewhere in the app instantiates a new MessageBoxDialog. It takes two string arguments so that the calling code can send it the desired title and message.

The second is WindowsLoaded(), which runs when the window displays. All this does is give the focus to the OK button. That way, the user can tap Enter or Space to close the window. (They can also press Esc, as I made the OK button the Default button and the Cancel button.)

The third is a Click() event handler for the OK button. The other custom dialogs all have two or more buttons, so there’s more work do to as the code has to know which button the user pressed. But this dialog only has one button, so all it has to do is close the dialog. Simple.

That’s it. The other custom dialogs have button Click() event handlers, too, and while each works a little differently, the main goal is the communicate back to the code which button the user pressed. But that doesn’t matter here. There’s only one button, so there’s no real choice. All the user can do is close the window.

With MessageBoxDailog.xaml and MessageBoxDailog.xaml.cs added to the project, I could move on to Goto line. If you look at the code for GoToCommand_Executed in MainWindow.xaml.cs, you’ll see that there’s an if-then loop that checks to see whether the user chose is available in the current document. If it isn’t, it runs the else clause, which displays a MessageBox.

The system MessageBox requires just a single line of code. My custom version requires more than that, but it’s not in any way complex. It instantiates a new MessageBoxDialog (while passing in the desired title and message) and then displays the dialog modally, so the user has to deal with it before doing anything else.

That Owner = this bit may not be immediately obvious, however. That’s required to make the dialog appear centered horizontally and vertically on top of its parent, which is MainWindow. If you look at the XAML code again, you’ll see that the MessageBoxDialog window sets its WindowStartupLocation property to “CenterOwner.”
To test the dialog, I just ran the app, opened Go to line (Ctrl + G) and entered a number higher than 1, since it’s a blank document and that’s the only line. Bingo.

It may get a little fine-tuning in the future, but I tried to make it similar to the dialogs Notepad uses, of course. So the overall size of the window and OK button are purposeful.
Find/Replace required a bit more work, but that was on me. Among the many issues with .NETpad, there’s still a lot of code duplication that needs to be consolidated despite my earlier clean up attempts. And this is one example: There are three places in the code–annoyingly, two are in MainWindow.xaml.cs, while one is in Backend.cs–that fire this dialog.
To partially fix this–I suspect more consolidation would help throughout all the Find/replace-related methods—I created a FindFailed() method in Backend.cs that I could then call from those other three places that were displaying a MessageBox.

It works like the Go to line MessageBoxDialog, of course, so it’s straightforward.
Then I just replaced the code in the else clause with a call to FindFailed() in three places in the app:
For example:

Testing this was more of the same: Use Find (or Find/Replace) and try to find a text string that isn’t anywhere in the text.

Still, embarrassing. Further modularizing the code and reducing (removing?) code duplication is important to me and something GitHub Copilot seems to be particularly helpful with. So this will come up again.
This was arguably unnecessary, but I also use a system MessageBox in exception handling, typically related to files, so the app displays an error message when something goes wrong. It’s been a while since I’ve even seen that happen, which is why this may be unnecessary. But what the heck. My ADD won’t let me ignore this.
I searched the source code for those exception handling try/catch blocks and found several of them. And so I replaced them all as well.

Well, this was a painless detour and a small step forward at best. But it’s still a step forward. I’ve updated the code on GitHub, so anyone who downloads it now will get the new MessageBox custom dialogs. 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.