
Tied to this, I’m considering doing things a bit differently with the 2025 version of .NETpad. That is, rather than wait until this version of the app is “done” to post it to GitHub, , I will likely publish this version as I work on it, perhaps after whatever major milestones. So the version I have now, for example, might be a good candidate, at least once I “finish” my code quality pass.
The problem is, I can’t stop screwing with it.
As I noted in , I have been further modularizing the code with the vague aim of minimizing the code in event handlers (which are all found in MainWindow.xaml.cs) and expanding my use of helper methods and, in doing so, reducing code duplication. In doing this work, I kept running into a familiar pattern in which most of the helper methods I had created–Save(), SaveAs(), NewDocument(), OpenDocument(), and so on–could be improved by changing them to return a value of some kind, usually a bool (Boolean, which can be true or false), instead of a not doing so (using a void return type). This allows me to determine whether whatever that method does was successful, which is obviously useful.
As I also noted in , I’ve been making tentative first steps into using AI to help me improve my code quality. As is the case with all my work, I don’t use AI enough, and I’m not using it as effectively as I could. But the inadvertent full-project code assessment I made with was particularly interesting to me. It confirmed some of the work I had already done–including the increased modularization–but it also suggested I could do more.
So let’s start there.
Yesterday, I took the advice I got from Cursor (really, from Anthropic Claude) to heart and created two more source code files that now contain topic-specific code: AppSettings.cs for all application settings-related code (right now, just two huge helper methods, LoadSettings() and SaveSettings()) and FileOperations.cs for all the file-related helper methods (Save(), SaveAs(), NewDocument(), etc.). This lightened up Backend.cs considerably–this file now contains helper methods related to text handling, confirmation dialogs, find and replace, and a few other random things–so I guess there is a readability gain here. I also worry about their being “too many” of these files, in that I often stare at Visual Studio, wondering where I can find my own source code. But, OK.
One specific recommendation from Cursor/Anthropic was stuck in my craw: It noted that there was a lot of code duplication in the Auto save code and that I could reduce that redundancy. This felt vaguely familiar, and when I looked at the code, I reacquainted myself with how I had implemented this functionality. There are several main functions:
AutoSaveMenu_Click() – This is the event handler for the Auto save menu item. It creates an Auto save custom dialog, displays a message about enabling/disabling this feature (depending on its state at the time), and then calls AutoSaveEnable() or AutoSaveDisable() if the user elects to enable/disable Auto save. There is a lot of code in there for something that, at its core, is pretty basic. It’s just a toggle, really.
AutoSaveEnable() – This is the helper method that enables Auto save and changes all the relevant UI controls to indicate the change in state. (The Auto save menu item is checked, the Auto save status bar TextBox is updated, and the Auto save Toggle button in settings is set to On.) Enabling Auto save also enables the timer, so that Auto save occurs on what is now a set schedule (every 30 seconds).
AutoSaveDisable() – This is the helper method that disables Auto save and changes all the relevant UI controls to indicate the change in state. (The Auto save menu item is unchecked, the Auto save status bar TextBox is updated, and the Auto save Toggle button in settings is set to Off.) Disabling Auto save also disables the timer.
Prompted by the AI, I suddenly saw all this code–too much code in AutoSaveMenu_Click() and the same basic code in the two helper methods–and thought it would be easily to “fix” this by making a single AutoSaveToggle() helper method that would simply reverse the Auto save settings and UI controls when called. And like an idiot, I decided to simply code that myself without consulting AI. Habits die hard, I guess.
In the current version of .NETpad, AutoSaveEnable() looks like so.

And since AutoSaveDisable() is nearly identical, I could use this code as the basis for a new AutoSaveToggle() method. If you break down what needs to happen, it amounts to:
Toggle Auto save on or off
Update the three UI controls accordingly
Toggle the timer on or off
Call SaveSettings() so that the new Auto save configuration is saved to settings
Simple. Maybe.
My original thought was that AutoSaveToggle() could accept a single parameter, a bool, that would indicate whether Auto save should be enabled or disabled. Like so.

And then I could use that value to change the app-level Auto save variable (App.AutoSave) and the timer state accordingly. And also some of the UI controls that map to true/false. For example.

That’s most of the code that this method needs. But there are two other UI changes to make. The Auto save Toggle button in settings has to change its textual display (it toggles between “On” and “Off”). And the Auto save TextBox in the status bar has to change its display too (it toggles between “”Auto save: On” and “”Auto save: Off”). That doesn’t seem like a hard computer science problem. If OnOff is true, then the dynamic text I need is “On,” and if it’s false, then the text is “Off”. Easy.
This could be a set of if-else blocks, but I was hoping for something a bit less wordy. C# has a that one can use to perform this kind of test with less code, so I figured I could use that. Of course, I’d have to figure it out first, since I never use this kind of code. But the Microsoft Learn documentation linked to above has a nice shorthand for remembering how it works:
is this condition true ? yes : no
Here, the ternary conditional operator “?” evaluates the expression to its left. If it evaluates to true, then the code after the “?” and before the “:” runs If it evaluates to false, then the code after the “:” runs.
The Auto save Toggle button in settings is called AutoSaveToggleButton. In addition to checking/unchecking it, I have to change its text. So I might use code like the following
AutoSaveToggleButton.Content = OnOff ? “On” : “Off”;
Simple. And then the slightly more complicated Auto save TextBox in the status bar, which is named AutoSaveText. This might be set like so:
AutoSaveText.Text = “Auto save: ” + (OnOff ? “On” : “Off”);
And so the entire AutoSaveToggle() helper method might thus look like so:

Does it work?
Well, first I had to call it. Visual Studio told me that AutoSaveEnable() is called twice in the codebase, while AutoSaveDisable, curiously, is called three times. Each occurs in MainWindow.xaml.cs. So I had to hunt those down next. Fortunately, four of the five references are in AutoSaveMenu_Click(), which makes sense. (The stray additional call to AutoSaveDisable() is in ResetButton_Click(), which actually makes sense. Fixing that was simple enough: Just call AutoSaveToggle() and use a false value as the parameter.)
Ignoring the fact that AutoSaveToggle() probably needs some other additions related to multiple tabs, I then focused on the bigger task at hand. Changing AutoSaveMenu_Click() to use AutoSaveToggle(). And this work proved a bit more challenging. The problem is that this event handler (in the current app version) is a lot of code. It’s not complex code. But it is a lot of code.

It’s not just a lot of code. It’s a lot of repetitive code. Surely this refactoring would result in a lot less code in that event handler. Which you may recall is a big goal of mine for this app version: As little code in the event handlers as possible.
But what would that look like?
This event handler displays an Auto save custom dialog. The text it displays varies depending on whether Auto save is enabled. If it is, the dialog prompts you to disable it. If not, it prompts you to disable it. The user can click an Enable/Disable button to change the status of the feature. Or they can click a Cancel button and not make any changes.
The beginning bit is unchanged.

But now we have to do something with Auto save if the user clicks Enable/Disable. This one took me a while, but in the end, I came up with the following.
This is minimal-ish. I create an Auto save dialog and display it. The result is tested twice (for being null, which it won’t be, and to see whether its true). If the result is true, then the user clicked Enable/Disable, and that means we need to change the setting using AutoSaveToggle().
So that should work fine. Right?
Well, no.
What I found in testing this was that the value of App.AutoSave does change correctly as the user enables/disables this feature. But none of the related UI changes at all. For example, when I disabled Auto save, the following was true:
The Auto save menu item remained checked.
The Auto save Toggle button remained enabled (checked) and its content was “On”.
The Auto save TextBox in the status bar read as “Auto save: On”.
Each of those was incorrect.
This was too much for my fried brain yesterday. So when I woke up this morning, I looked at it with fresh eyes, hoping to quickly find the problem. Instead, I found a logic error I can’t explain. The result? AutoSave works properly again using this new code. But I don’t know why.
Rather than go through all the changes I made in order, here’s what I ended up with.
A simplified version of the AutoSaveMenu_Click() event handler. This version tests result for being null and true in a single line, which is nice.

A simplified version of AutoSaveToggle() that no longer uses a bool parameter, which I found to be unnecessary. Now I just use the value of App.AutoSave directly everywhere. (What’s missing there is any code that changes the value of App.AutoSave. But the value does change. That’s the bit I don’t understand.)

And then a minor change to ResetButton_Click() that explicitly sets App.AutoSave to false before calling AutoSaveToggle().

And … yeah. It “works.” But logically, it shouldn’t: I never explicitly toggle the value of App.AutoSave anywhere that I can find. It just toggles. God help me.
Except, of course, that I do toggle App.AutoSave somewhere. Of course I do. This is C#, not black magic.
Looking in AutoSaveDialog.xaml.cs, I found a ToggleAutoSaveButton_Click() event handler. This is what fires when the user clicks—wait for it—the Enable/Disable button in the Auto save custom dialog. It explicitly toggles the value of App.AutoSave. And that’s why I was getting the opposite results each time I tried to toggle Auto save. Sigh.

It’s not 100 percent clear “where” that code should be. But I don’t like that. So I deleted that block of code. And then I re-added the App.AutoSave toggle to AutoSaveToggle(). That feels like the right place or that code.

And … yikes. That’s how I spend my weekends. Hours of work, and what I’ve done is improve the code, which is nice, but not changed the user experience. I guess that’s a classic refactoring experience. But I had expected it to come together more quickly.
That was just the latest change, so I wrote it up while it was still fresh in my brain. Many of the other changes I’ve made are … fuzzier.
A few I can recall.
For example, I use the DocumentTab class to store all the document state information associated with each tab. Each tab–a WPF TabItem control–had a Header block and a Content block. The header is what you see in the tab, the text that represents the document name and the Close tab button, contained in a Grid. The header is–was–a Textbox I used to contain a copy of the contents of that tab’s document. I write was there because I ended up killing the content block for each TabItem. It’s not necessary.
This had been in the back of my mind for a while. As I coded the multiple tabs and documents, I kept wondering if that TabItem content was redundant. (I had had a few comments in the code to the effect of, “is this necessary?”) Worse, its presence was causing a UI layout error. I was hiding the TextBox in the Content rather than collapsing it, and if the document (text) it contained was long enough, the hidden TextBox would take up (empty) space in the UI, causing the New tab button to move over to the right.
Changing the TextBox’s Visibility property to Collapsed solved that problem, but it got me wondering. Do I need this? And how often–and where–was I even using it? Pretty quickly I discovered that it was redundant, as I had wondered, and so I exorcised it from the code. Now, the TabItem(s) don’t have a Content item of any kind. And the DocumentTab associated with each TabItem is all that’s used–and needed–for document management. This makes sense: That’s literally what DocumentTab is for, after all.
It’s also good from a readability perspective. The code to create each TabItem is long enough as it is, and any reduction there is a good thing.
I mentioned how I’ve been transitioning many of my helper methods to use a return value, typical a bool. This helps me reduce code repetition, as I can now check the return value of these methods when called and find out whether they actually accomplished their mission. I didn’t go into this with a plan per se. Instead, I found myself running into instance after instance in which it was clear that I needed to know if whatever operation succeeded.
Save() and SaveAs() are, perhaps, the best example. And that’s because there’s an interim step in which the user is prompted to save a document in various circumstances, and in each case, they can choose to save, not save, or cancel. And if they cancel, that should interrupt whatever action was taking place.
Consider this simple scenario. You’re running the app, have edited the text in just a single unsaved document in single tab, and you click the app’s Close window button. Without any checks, the app would just close, and you would lose whatever was in the TextBox. But it checks, of course. It uses the TextIsChanged property in the DocumentTab object to track whether the document has been edited. And it uses DocumentIsSaved to track whether this document has ever been saved to disk.
If TextIsChanged is true and DocumentIsSaved is true, I call Save().
If TextIsChanged is true and DocumentIsSaved is false, I call SaveAs().
The first one is simple. It just saves without prompting the user and we can move on to the next step.
The second one is the problem. The user is prompted: Do you want to save this document? There are multiple possible outcomes here.
If they choose “Save,” a Save as dialog appears.
If they save the document, we can move on to the next step.
If they cancel, we have to abort the entire operation. In this case, that means not closing the app.
If they choose “Don’t save,” the document is not saved and app is closed.
If they choose “Cancel,” the document is not saved and the app is not closed.
Clearly, I needed a way to determine whether the Save and SaveAs occur. And so now these two methods return a bool value: True if the document was saved and false if not. Both methods are called four times each elsewhere in the code, and depending on the need at the time, that code can use that return value or not.
For example, in the SaveCommand_Executed() event handler–which triggers when the user selects File > Save or types Ctrl + S–I don’t need to worry if anything works. I can just call Save() and SaveAs() as needed.

But in DisplayConfirmationDialog(), I need to use the return value. This is the method that runs when the app needs to display that Save confirmation custom dialog. And per the bulleted list above, what the user chooses there matters, and the app can now act accordingly in a more elegant matter. This is just part of that code, and it most likely will be made more elegant later. But it works.

There are more examples and, I suspect, there are more to come. But it’s interesting (to me) how much using return values like that can help.
I will continue this work and suspect I will continue running into ways in which I can improve the code through more modularity. But I will also recreate this version of the app from scratch ahead of a potential GitHub publication, so anyone who wants to try the tabs-based version of the app in pre-release form can do so. Fit and finish is difficult enough as it is, but it will be particularly elusive with this more complex version of the app. Consider the issue of “remembering” where the cursor is in each document/tab and which text, if any, is selected. It’s getting there.
Generally speaking, my hope is that I can “check off” each method in the code base, in turn, meaning move on from them as they achieve whatever level of quality, knowing/hoping that I don’t have to touch them further. I can’t even guess how long this will take, but I figured I’d dfinish this initial implementation of tabs before we left Mexico in late April/early May. Barring any unforeseen issues, I should have no trouble meeting or beating that schedule.
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.