Modernizing .NETpad: Application State (Premium)

Developers often utilize design patterns that logically separate an app’s presentation and business logic and use a third component to mediate between the two. The Windows Presentation Foundation (WPF) straddles the evolution of these design patterns. And its use of XAML files for declaring user interfaces tied to associated “code behind” C# files for event handlers was innovative and useful enough to have stood the test of time. So much so that Microsoft continued using this same model in subsequent app frameworks like Metro, UWP, MAUI, and the Windows App SDK.

WPF itself has also stood the test of time, as it remains a viable app framework today, almost 20 years after its introduction. And thanks to its popularity, Microsoft and various third parties have adapted WPF to adhere to popular design patterns over time. The most popular of these at first was something called the Model-View-Controller (MVC) pattern, in which the Model component handled internal logic, the View component handled the user interface, and the Controller acted as the mediator between the two. (NeXT used MVC and then brought this system to Mac OS X when that company acquired it.)

In more recent years, MVC has been supplanted by the Model-View-ViewModel (MVVM) design pattern, which was invented by two software architects at Microsoft in the early 2000s. And while I have no direct memory of this, it appears that it arrived roughly in-sync with WPF, based on the date of this archived MSDN blog post. At that time, the theory was that a professional application would be designed by a team of people that would include at least one designer who would work on the app UI (in XAML, in this case, but using a graphical tool that output the code) while at least one traditional developer would handle the necessary event handlers and other business logic, typically in C#. But there was another important aspect of MVVM that made it particularly well-suited to WPF: Data binding.

I’ve referenced data binding here and there throughout this series, mostly to voice my continued ignorance of how it works, despite it being so central to WPF. I’m still trying to understand WPF data binding, but when I first created .NETpad, I felt this app was so simple that learning MVVM and data binding was unnecessary, and that the overhead would outweigh the benefits. That said, I had to use a bit of data binding, even in that first WPF version of the app: The Fonts dialog–and now the font interface in app settings in the latest version–binds to the SystemFonts class in .NET to discover and display the available fonts, and to allow the user to change the font used by the app.

Tied to this, I’ve written about my refactoring of the code in .NETpad to be more elegant and efficient. As part of this effort, I separated the non-event handler code in the app into a separate C# file (backend.cs). I did this to better organize the code more logically, but if you were feeling generous, you might view it as a very primitive design pattern. Whatever it is, I’m happy with the change, and with other coding improvements I’ve made on this pass with the app. But there are things that still bother me, some of which are tied to my lack of sophistication–again, not a professional developer–and I’ve been wondering about the best approach to take for something I think of application state.

To my mind, application state is data that pertains to the application that I–or, I guess, the app itself–needs to keep track of at runtime. But I also separate this into two kinds of application state. There’s state that’s determined by the user preferences and saved to the per-user app settings. Things like whether spell checking or word wrap is enabled, for example. And then there is other state that isn’t tied to the app’s settings. Temporary state that exists only at runtime and yet still needs to be tracked. For example, I keep track of whether the current document is saved, the name of the current document, and whether the text has changed, among several other things.

My current, unsophisticated, approach is to use what I think of as global variables–variables that are defined in the root of the MainWindow class–to store both kinds of state. (They’re not really global variables per se, but close enough.) The three examples I noted above are defined like so in MainWindow.xaml.cs:

bool DocumentIsSaved = false;
public string DocumentName = “Untitled.txt”;
public static bool TextHasChanged = false;

I never liked doing this. But when the app was simpler, there were only a handful of these variables, and I rationalized this simpleminded approach to a combination of the app’s simplicity and my personal limitations. But since then, the app has gotten bigger and more functional, and I’ve had to add more and more of these global variables. And as I work towards transforming it to use a tab-based user interface, I will need even more. There’s a lot of state to keep track of.

All along, I’ve been wondering about this, casually researching the topic now and again. Is there a better way? A more sophisticated way?

Eventually, I asked Raphael. He mentioned MVVM, which I had researched, and agreed that it was perhaps overkill for this particular app. I asked about just using the app’s per-user settings functionality–which is more about user preferences than app state–or perhaps another settings file, but he was leery of reading and writing to disk so often from a performance perspective.

He was OK with my basic approach, though that was probably more about working within my limitations than agreeing it made sense generally. But he touched on something that had been bugging me: Variables that are global to MainWindow are just global to MainWindow. That is, they’re not global to the app. And while I can reference them from other classes–such as those used by other app windows, like the Save confirmation dialog (ConfirmationDialog)–doing so is tedious. First, I have to identify the variable as being public (as with public string DocumentName = “Untitled.txt”; ). And then I have to use a fully qualified name to access that variable from other classes. Like this:

ConfirmTextBlock.Text = “Do you want to save the changes to ” +
((MainWindow)Application.Current.MainWindow).DocumentName + “?”;

This looks inelegant to me. And as I converted my various panes to standalone dialogs as previously described, this type of code came up again and again. That, combined with the needs of the coming tab-based UI, is what triggered this rethinking.

Rafael discussed using class properties, which felt complex to me. Or just declaring these variables at the app level, as opposed to in MainWindow. That was … interesting. Maybe. It’s not much more sophisticated than my current approach. And it would require two changes per variable. First, I would need to move the declaration from MainWindow.xaml.cs to App.xaml.cs and add the static keyword to ensure that only one copy exists while the app’s running:

public static bool TextHasChanged = false;

Second, I’d have to change how I reference these variables everywhere, including in MainWindow. For example, where I would normally write something like the following:

TextHasChanged = false;

I would now need to use:

App.TextHasChanged = false;

This isn’t the end of the world. But is it worth it? Does this buy me anything?

I think it does. It’s subtle, but it does. It makes it clear which state variables are truly global. It gives me a way to organize those things when the app first runs and then not worry about them when it closes: The per-user settings will still be saved normally and in the same places/times. And having embraced a multi-window interface, with separate standalone windows for Auto Save, Save confirmation, Find/Replace, and Go to line, the code in those classes will be less convoluted and easier to read. The code in MainWindow will be no less easy to read, it will just require a little work to update it. The code everywhere will be more consistent.

This all appealed to the ADHD part of my brain. So I decided to make that change, with the idea that it was right for the app, especially given the coming updates for tabs. And good for my peace of mind. So far, I’ve only identified several variables that warrant this change. But perhaps there will be more as I continue with this project.

Now if I could just figure out data binding, I’d be all set.

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