A WPF/MVVM Countdown Timer

Introduction

This article, describes the construction of a countdown timer application written in C# and WPF, using Laurent Bugnion’s MVVMLight Toolkit. This article is based on the work of some previous articles I’ve written:

As usual most of the code shown in this article is elided, particularly since no-one likes scrolling through 5 screens worth of XAML to see one the one line of interest. Please download the source zip file to see the whole thing.

Requirements and Features

The Countdown Timer is going to be relatively simple:

  • The starting time can be chosen by the user.
  • Notify the user visually (in the application and task tray) and audibly.
  • The application has settings that the user can change.
  • The Windows 7 taskbar icon shows the progress of the timer.

The original motivation for this was that I came across the Pomodoro Technique whilst browsing the web and thought it would be fun to write a countdown timer that could be used for this. It is, in short, a ‘getting things done’ idea which can be boiled down to:

  • work for 25 minutes
  • break for 5 minutes
  • repeat

So I decided that the default setting for the timer is 25 minutes, and that it should record the number of completed countdowns unobtrusively, should someone wish to use this application in that way.

Choosing the Underlying Timer

We use the WPF DispatchTimer to perform a count. We are not making any guarantees about the accuracy of the timer.

In fact neither does the documentation:

Timers are not guaranteed to execute exactly when the time interval occurs, but they are guaranteed to not execute before the time interval occurs. This is because DispatcherTimer operations are placed on the Dispatcher queue like other operations. When the DispatcherTimer operation executes is dependent on the other jobs in the queue and their priorities.

By leveraging the .NET framework, we use a TimeSpan that allows us to increment, and importantly, decrement by a specified amount. We then simply decrement our starting value every time the DispatchTimer ticks, until we get a negative TimeSpan, and then we stop.

The code is written in such a way that the TimerModel is just a concrete implementation of ITimerModel and the concrete instantiation of an ITimerModel is generated from a single factory method: in other words you could write your own ITimerModel derived class instead and update the factory method as required (e.g. use System.Threading.Timer instead).

MVVM

Since all ‘good’ WPF applications use MVVM to structure themselves, I’ll attempt to automatically make this application ‘good’ by default, by using an MVVM framework!

What does this mean? The application will be divided into:

  • Views – XAML-only layouts that the application uses: i.e. the GUI and all its windows!
  • ViewModels – translate the data between the Views and the Models.
  • Models – the actual code that does the work (and everything else).

If you find this confusing or want to know more, please see another of my articles: WPF/MVVM Quick Start Tutorial.

Application Settings

All applications have settings and this one is no different: to persist the application’s settings, we take advantage of the class System.Configuration.ApplicationSettingsBase. This is subclassed for the WPF application when you create it, so you can then just address the application settings programmatically, for example:

_timer.Duration = Properties.Settings.Default.Duration;

where we have created a Duration property.

In the same way that we hide the implementation of the Timer behind a ITimerModel interface, we also use an interface called ISettingsModel class, and use a concrete instances called SettingsModel, along with a factory method to retrieve an instance of the class. This gives us the option, as before, to change the settings backing store, to something else in the future (ini file anyone?).

Updating Settings Between Application Versions

To cater for updates to the application we can use the following method: define UpgradeRequired in our settings, and set to True by default. We then use:

if (Properties.Settings.Default.UpgradeRequired)
{
  Properties.Settings.Default.Upgrade();
  Properties.Settings.Default.UpgradeRequired = false;
  Properties.Settings.Default.Save();
}

to force the upgrade of the application settings only when the UpgradeRequired flag is true. For newly versioned assemblies, all settings take their default values, this code is triggered, and the settings are copied from a previous application version, if it exists, to the new one.

It is worth noting that for this ‘trick’ to work, you always need to define this field in your application settings in the very first version of your application.

The Views and ViewModels

Ther application has several views that are all UserControls and hosted in the MainWindow. This means no pop-up dialogs! They are:

  • The main TimerView
  • The SettingsView
  • The AboutView

with the corresponding ViewModels:

  • The TimerViewModel
  • The SettingsViewModel
  • The AboutViewModel

Changing Views and Messaging

As we want to use ‘separation of concerns’, or ‘encapsulation’ (if you prefer), we do not want view-models to communicate directly. In order to do this, we simply use message passing, in other words:

The MVVMLight Toolkit provides us with a singleton Messenger class that we can register message consumers and message producers with. So to raise an ‘event’ in one view model from another, we simple pass a message, for example:

public class MainViewModel : ViewModelBase
{
    public MainViewModel()
    {
        //  Lastly, listen for messages from other view models.
        Messenger.Default.Register<SimpleMessage>(this, ConsumeMessage);
    }

    private void ConsumeMessage(SimpleMessage message)
    {
        switch (message.Type)
        {
            case MessageType.TimerTick:
                WindowTitle = message.Message;
                break;
            // ....
        }
    }
}

and in the TimerViewModel:

public class TimerViewModel : ViewModelBase
{
    private void OnTick(object sender, TimerModelEventArgs e)
    {
        Messenger.Default.Send(new SimpleMessage(MessageType.TimerTick, TimerValue));
    }
}

What this achieves is as follows: the TimerViewModel updates the TimerView countdown clock in the main window’s ContentControl, but we want to update the window’s title to also show the countdown. The main window View is bound to the MainViewModel, so to do this, and to keep the view-models separate we pass a message containing the time remaining. The reason we update the window title bar is discussed a little later.

The TaskBar Preview and the Window Title

As you can see in this screenshot:

The countdown value is shown in the taskbar item thumbnail, and in the main window’s title. The reason we update the window’s title is that when a window is minimzed, the taskbar item thumbnail is not updated by Windows, so if you were to hover your mouse pointer over the icon on the task bar when the item is minimized, the thumbnail preview will display the countdown at the time you minimized the window. Fortunately, the title of the window is updated in the thumbnail preview, so we ensure that we update that to provide a visual clue to the user.

TaskBar Messages

We need a second message type to comminicate task bar progress updates in Windows 7: since the MainWindow ‘view’ is bound to the MainViewModel, we need to receive messages from the TimerViewModel that are appropriate to update the task bar progress indicator. Fortunately this is relatively straightforward, and once again we make use of the Messenger.Default.Register and Messenger.Default.Send pattern we saw earlier.

The second message class is simply:

public class TaskbarItemMessage
{
    public TaskbarItemMessage()
    {
        State = TaskbarItemProgressState.None;
        Value = -1.0;
    }
    public TaskbarItemProgressState State { get; set; }

    public double Value { get; set; }

    public bool HasValue { get { return ! (Value < 0.0); } }
}

Our TimerViewModel just send instances of these messages and the MainViewModel receives them, and via the magic of data-binding, between the view model (MainViewModel) and the view (MainWindow) the taskbar progress indicator just updates:

<Window x:Class="Btl.MainWindow"
        DataContext="{Binding Main,
                              Source={StaticResource Locator}}">
    <Window.TaskbarItemInfo>
        <TaskbarItemInfo ProgressState="{Binding ProgressState}" ProgressValue="{Binding ProgressValue}">
            <TaskbarItemInfo.ThumbButtonInfos>
                <ThumbButtonInfoCollection>
                    <ThumbButtonInfo Command="{Binding PlayCommand}"
                                     Description="Start"
                                     DismissWhenClicked="False"
                                     ImageSource="Resources\icon.play.png" />
                    <ThumbButtonInfo Command="{Binding PauseCommand}"
                                     Description="Pause"
                                     DismissWhenClicked="False"
                                     ImageSource="Resources\icon.pause.png" />
                </ThumbButtonInfoCollection>
            </TaskbarItemInfo.ThumbButtonInfos>
        </TaskbarItemInfo>
    </Window.TaskbarItemInfo>
    <!-- ELIDED  -->
</Window>

Since the TaskBarItemInfo thumbnail previews offer us more than just the preview, we can add a thumbnail ‘Start’ and ‘Pause’ button (just like Media Player), so we can control the countdown timer from the thumbnail preview, hence the ThumbButtonInfo elements above.

A Note on the UI Design

There is some method to the madness of the Countdown Timer UI: since the Play and Pause buttons are likely to be the most used, they are the largest, then the settings and reset buttons are smaller so they are less likely to be clicked on. The ‘About’ window is accessed by a small ‘?’ in the bottom right hand corner.

Similarly, the ‘Ok’ and ‘Cancel’ buttons are widely separated in the Settings view so it is clear which one you want to click on.

And lastly, aside from the button icons (play, pause etc.), I’ve left the theming of the application alone, so that the OS can choose how to theme it. Of course, since this is an MVVM application, you can take the source code, fire up Blend, and change it however you like.

There are even some third-party libraries that will do a lot of the work for you, e.g. MahApps.Metro.

Bonus Features

In the apps section of this site there is an MSI installer for anyone that cares to use it and just wants to install the timer.

All the source code is also on github and you are free to fork it, copy it, break it, etc. The MSI installer project uses Installshield, so it is part of the solution hosted on github, but not included in the zip files above (in case you, the reader, do not have it installed).

On CodeProject

This article is cross-posted on Code Project

A XAML-Only Font ComboBox

I needed a simple ComboBox to select a FontFamily in a WPF application (I don’t care about the font-weight). After some searching I found Pete O’Hanlon’s article, describing what I wanted.

So why another (short!) article? The first commenter in the article suggested this:

<ListBox ItemsSource="{Binding Source={x:Static Member=Fonts.SystemFontFamilies}}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Label FontFamily="{Binding .}" Content="{Binding Source}" />
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

as an alternative, which made me think about combining the two as a pure XAML solution that you can cut and paste (as Pete’s code has a tiny bit of code-behind). In order to create the XAML solution I found out a few interesting things that I thought I would share in a real example (as I’m still getting to grips with the many facets of WPF).

Show Me The XAML!

Here it is, in its entirety:

    <ComboBox 
              xmlns:ComponentModel="clr-namespace:System.ComponentModel;assembly=WindowsBase"
              ItemTemplate="{DynamicResource FontTemplate}">
        <ComboBox.Resources>

            <CollectionViewSource x:Key="myFonts" Source="{Binding Source={x:Static Fonts.SystemFontFamilies}}">
                <CollectionViewSource.SortDescriptions>
                    <ComponentModel:SortDescription PropertyName="Source" />
                </CollectionViewSource.SortDescriptions>
            </CollectionViewSource>

            <Style x:Key="FontStyle">
                <Setter Property="Control.FontFamily" Value="{Binding Source}" />
                <Setter Property="Control.FontSize" Value="16" />
            </Style>

            <DataTemplate x:Key="FontTemplate">
                <StackPanel VirtualizingStackPanel.IsVirtualizing="True">
                    <TextBlock Style="{StaticResource FontStyle}"
                               Text="{Binding Source}"
                               ToolTip="{Binding Source}" />
                </StackPanel>
            </DataTemplate>

        </ComboBox.Resources>

        <ComboBox.ItemsSource>
            <Binding Source="{StaticResource myFonts}" />
        </ComboBox.ItemsSource>
    </ComboBox>

You should be able to cut’n'paste this directly into your code. You would then bind the ComboBox‘s SelectedValue to a property of your choice. The SelectedValue is of type System.Windows.Media.FontFamily.

What is Going On?

There are several things going on that we need to describe. Beware! More verbose XAML!

A Sorted List of Fonts

Skipping directly to the ComboBox.Resources section: we get the full collection of system fonts. However, by default they only come partially sorted (by FamilyName), so we sort them into our own collection called myFonts. We do this by importing the ComponentModel namespace via this XAML markup:

xmlns:ComponentModel="clr-namespace:System.ComponentModel;assembly=WindowsBase"

and then create our own collections sorted by the Source property (which is the font family name):

<CollectionViewSource x:Key="myFonts" Source="{Binding Source={x:Static Fonts.SystemFontFamilies}}">
    <CollectionViewSource.SortDescriptions>
        <ComponentModel:SortDescription PropertyName="Source" />
    </CollectionViewSource.SortDescriptions>
</CollectionViewSource>

Data Template

We declare a simple template that renders the fonts in their own type face, and provides a tooltip, within the ComboBox.

Static Resources

Lastly we bind the ComboBox.ItemsSource to our sorted collection of fonts, myFonts using the long-hand XAML binding. Why do we do this last, and not directly as a ComboBox attribute?

The ItemsSource attribute requires that it is bound to a static resource. Suppose we do this:

    <ComboBox 
              xmlns:ComponentModel="clr-namespace:System.ComponentModel;assembly=WindowsBase"
              ItemTemplate="{DynamicResource FontTemplate}"
              ItemsSource="{Binding Source={StaticResource myFonts}}">

We get an exception thrown:

“Cannot find resource named ‘myFonts’. Resource names are case sensitive.”

as myFonts has not yet been declared.”

We could of course move our font collection to the UserControl/Window/Application Resources section, however in this example we only have one font combo box, so it is nice to have it within the ComboBox.Resources section.

You might also try setting the ItemsSource to reference myFonts dynamically, via:

    <ComboBox 
              xmlns:ComponentModel="clr-namespace:System.ComponentModel;assembly=WindowsBase"
              ItemTemplate="{DynamicResource FontTemplate}"
              ItemsSource="{Binding Source={DynamicResource myFonts}}">

This also fails with the exception:

“A ‘DynamicResourceExtension’ cannot be set on the ‘Source’ property of type ‘Binding’. A ‘DynamicResourceExtension’ can only be set on a DependencyProperty of a DependencyObject.”

So in answer to our question: as XAML has a ‘one-pass compiler’, a StaticResource has to be declared lexically before it is referenced: if we declare the binding last, then we can create our sorted list of fonts StaticResource, within ComboBox.Resources, and then bind to it within the XAML of the ComboBox, hence this piece of XAML:

<ComboBox.ItemsSource>
    <Binding Source="{StaticResource myFonts}" />
</ComboBox.ItemsSource>

Using This XAML Snippet.

As mentioned above, if you intending on using this XAML (and using the font combobox multiple times), move the sorted font collection:

<CollectionViewSource x:Key="myFonts" Source="{Binding Source={x:Static Fonts.SystemFontFamilies}}">
    ...
</CollectionViewSource>

into your ‘Application/Window/UserControlResources` section, and put this attribute:

xmlns:ComponentModel="clr-namespace:System.ComponentModel;assembly=WindowsBase"

into the corresponding XAML document root.

A Final Word on Safe Font Usage.

Never, ever, choose Comic Sans. Ever.

Cross posted to Code Project

MVVMLight Using Two Views

In the previous article, I quickly showed how to create a single-view, single-window WPF application using MVVM Light. The trend in WPF applications is to have a single window holding multiple views so that there are less pop-up dialogs or child windows. This article shows how to construct a simple two view application using MVVM and WPF.

Getting Started

  • Requires VS2010
  • Ensure that you have Nuget installed.
  • Manage Nuget Package References and add MVVM Light
  • The example code for this article is on github.

Note that the XAML, in particular, is elided for brevity and you should go to the git repository for the original code.

Hosting Multiple Views

The application structure is similar to the previous article: we have a MainWindow, a ViewModelLocator, and a MainViewModel.

A picture is worth a thousand words, so without further ado, here is what the project structure looks like in VS2010:

The project is laid out in typical MVVM style: 3 folders for Models, ViewModels, and Views. In this case we do not have any Models so they can be ignored.

Starting with the Views: we simply have two UserControl XAML files, that have contain the views that we want to render. The first view is the one from the previous article. The second is just a text label.

All the work involved in rendering two different views for two different view-models happens in MainViewModel.cs, MainWindow.xaml, and App.xaml.

Looking at the MainWindow XAML, we see the following;

<Window x:Class="TwoViews.MainWindow"
        DataContext="{Binding Main,
                              Source={StaticResource Locator}}">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <ContentControl Content="{Binding CurrentViewModel}" />

        <DockPanel Grid.Row="1" >
            <Button Command="{Binding SecondViewCommand}"
                    Content="Second View"
                    DockPanel.Dock="Right" />
            <Button Command="{Binding FirstViewCommand}"
                    Content="First View"
                    DockPanel.Dock="Left" />
        </DockPanel>
    </Grid>
</Window>

As before, we use the ViewModelLocator to bind our Main view model to the MainWindow. This time, however, we have a ContentControl that binds to a new property called CurrentViewModel, and two buttons that bind to commands that switch the view models. Even though the buttons are labelled as switching the views, it is actually the view-models that are updated.

The next step in getting this to work, is implementing a DataTemplate, per view model that renders a View associated with a ViewModel. We do this in the App.xaml (though we could do it any Resource section we choose):

<Application x:Class="TwoViews.App"
             xmlns:views="clr-namespace:TwoViews.Views"
             xmlns:vm="clr-namespace:TwoViews.ViewModels"
             StartupUri="MainWindow.xaml"
             >
    <Application.Resources>
        <vm:ViewModelLocator x:Key="Locator"  />
        <DataTemplate DataType="{x:Type vm:SecondViewModel}">
            <views:SecondView />
        </DataTemplate>
        <DataTemplate DataType="{x:Type vm:FirstViewModel}">
            <views:FirstView />
        </DataTemplate>
    </Application.Resources>
</Application>

For example, this quite literally says ‘if my data type is FirstViewModel, then the WPF framework should render the FirstView UserControl.

So when the Content attribute of our the ContentControl is set to an object of type FirstViewModel the framework renders the correct View for us.

It should also be noted that because the Content attribute has been set to a particular ViewModel, for example FirstViewModel, it is also set as the DataContext for the view that is rendered, i.e. FirstView, and the data-binding between FirstView and FirstViewModel therefore work.

The last part of the application that wires all of this together is the MainViewModel class. Clearly we only want a single instance of each view model, so we just declare static instances of each one:

public class MainViewModel : ViewModelBase
{
    private ViewModelBase _currentViewModel;

    readonly static FirstViewModel _firstViewModel = new FirstViewModel();
    readonly static SecondViewModel _secondViewModel = new SecondViewModel();

    public ViewModelBase CurrentViewModel
    {
        get
        {
            return _currentViewModel;
        }
        set
        {
            if (_currentViewModel == value)
                return;
            _currentViewModel = value;
            RaisePropertyChanged("CurrentViewModel");
        }
    }

    public ICommand FirstViewCommand { get; private set; }
    public ICommand SecondViewCommand { get; private set; }

    public MainViewModel()
    {
        CurrentViewModel = MainViewModel._firstViewModel;
        FirstViewCommand = new RelayCommand(() => ExecuteFirstViewCommand());
        SecondViewCommand = new RelayCommand(() => ExecuteSecondViewCommand());
    }         

    private void ExecuteFirstViewCommand()
    {
        CurrentViewModel = MainViewModel._firstViewModel;
    }

    private void ExecuteSecondViewCommand()
    {
        CurrentViewModel = MainViewModel._secondViewModel;
    }
}

Note that in the CurrentViewModel property we also have to RaisePropertyChanged via the INPC interface that ViewModelBase defines. This is so that the data-binding works in WPF, i.e. when we click on the buttons the view changes: if this line is omitted, you cannot change the views by clicking on the buttons.

If we run the code we can now see that we can switch between the two views and both views maintain their state (as we are using a static instance of each):

Finishing Off

You might feel that the code above looks repetitive: it is. Many, if not all, MVVM frameworks provided ‘runtime assistance’ in automating this kind of thing. By that I mean that by naming your classes according to convention, e.g. by always using the ‘View’ and ‘ViewModel’ suffixes, MVVM frameworks heavily use reflection and can associate your views and view-models at run time. Indeed, even the MainViewModel above is often generalised into something that is provided by the MVVM framework.

Footnotes

Previous articles/further reading:

The example code is on github.

MVVMLight Hello World in 10 Minutes.

This article shows a trivial ‘Hello World’ MVVM WPF application using the MVVM Light library.

Getting Started

  • Firstly, start VS2010, and create a new WPF project.
  • Ensure that you have Nuget installed.
  • Manage Nuget Package References and add ‘MVVM Light’

MVVM Light has now added a ViewModel folder containing the MainViewModel and the ViewModelLocator.

Edit the Main Window

Simply add a button, and defer the DataContext binding to the ViewModelLocator (elided):

<Window x:Class="MvvmLightTest.MainWindow"
        DataContext="{Binding Main,
                              Source={StaticResource Locator}}">
    <Grid>
        <Button Command="{Binding ShowPopUp}" Content="Show Pop Up" />
    </Grid>
</Window>

Then in the MainViewModel we define the ShowPopUp command:

public class MainViewModel : ViewModelBase
{
    public MainViewModel()
    {
        ShowPopUp = new RelayCommand(() => ShowPopUpExecute(), () => true);
    }

    public ICommand ShowPopUp { get; private set; }

    private void ShowPopUpExecute()
    {
        MessageBox.Show("Hello!");
    }
}

Compile the code, and we get:

The MainViewModel inherits from the ViewModelBase class which also gives us the RaisePropertyChanged method, which we would call if we change the value of a property that we bind to (see this CodeProject article for more information). An example of property data-binding is also included in the example code.

How does all this work?

Firstly, our App.xaml contains an application wide instance of the ViewModelLocator:

<Application x:Class="MvvmLightTest.App"
             xmlns:vm="clr-namespace:MvvmLightTest.ViewModel"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" />
    </Application.Resources>
</Application>

We then defer the DataContext binding to the ViewModelLocator (elided) in the MainWindow:

<Window x:Class="MvvmLightTest.MainWindow"
        DataContext="{Binding Main,
                              Source={StaticResource Locator}}">
    <Grid>
        <Button Command="{Binding ShowPopUp}" Content="Show Pop Up" />
    </Grid>
</Window>

This simply returns the static instance of the MainViewModel held in the ViewModelLocator instance.

The example code is on github.

A WPF TimeSpan Custom Control

I have added yet another CodeProject article entitled A WPF Short TimeSpan Custom Control that builds up on my previous article that creates a simple spinner control.

The introduction to the article is here, but go to the CodeProject web site for the full article:

Introduction

In my previous two articles, I first described a simple short TimeSpan UserControl that used sliders to pick the hours, minutes, and seconds of a TimeSpan. In my second article I described a custom spinner control that could be used to replace the sliders.

In this third article, I will update the TimeSpan control to use the SpinnerControl, and make the TimeSpan control a custom control, rather than a UserControl (in particular so that we can apply custom themes to it). I refer to this as a ShortTimeSpanControl as it only represents a positive TimeSpan from 00:00:00 to 23:59:59. A full TimeSpan is described here:

A TimeSpan value can be represented as [-]d.hh:mm:ss.ff, where the optional minus sign indicates a negative time interval, the d component is days, hh is hours as measured on a 24-hour clock, mm is minutes, ss is seconds, and ff is fractions of a second. That is, a time interval consists of a positive or negative number of days without a time of day, or a number of days with a time of day, or only a time of day.

With the generic theme supplied, this is a selection control, where the user can choose a TimeSpan. As it is a custom control, you can apply any custom theme you like, and, perhaps, just make it a read-only control (interactively, that is), that updates its Value via data-binding.

….read the full article at A WPF Short TimeSpan Custom Control

A WPF Spinner Custom Control

I have added another article to Code Project: A WPF Spinner Custom Control which describes the process of creating a simple spinner control in WPF using the framework.

This follows up from my previous post where I created a simple UserControl to select a TimeSpan. In the absence of a spinner control I used sliders instead. Writing a spinner control has been an educational experience: whilst I have previously written controls, writing a new one from scratch and adhering to the various framework guidelines and conventions (to a degree) meant that I had to read through much more of the MSDN documentation than I would previously have taken a look at.

What makes the article a little different to some of the others out there, is that I try and mention each part of a custom control: the code, the generic theme, and then applying a custom theme to it.

A WPF/MVVM Countdown Timer on GitHub

I have started working on a simple countdown timer that is written in C#, XAML, and uses the ‘MVVM’ pattern. The v0.1 code is checked into GitHub, where you can download it, fork it, and play around (yes, I’m using semantic versioning). The purpose of this is to refresh my memory about XAML, and C#, and also to play around with CodeRush and Refactor! that make writing C# much easier.

The version 0.1 features are:

  • Countdown fixed and starts at 25 minutes.
  • Plays a start/stop sound using the SystemSounds.
  • Settings not implemented.
  • The window stays top-most.
  • The Windows 7 taskbar icon shows the countdown progress.

This will go up onto CodeProject, I expect, once I’ve finished it off. The icon, if you are interested, was created using Icon Workshop which, at the time of writing, has money off.

Wpf App Config location

I’m gradually getting up to speed on WPF. However, as expected in any language or platform these days, there are slightly thorny questions and answers that aren’t always easy to find. Here’s one to start with. Where is the location of the application settings file?

Add a reference to System.Configuration:

Configuration config =
  ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal);
if (config != null && !String.IsNullOrEmpty(config.FilePath))
  Console.WriteLine("Local user config path: {0}", config.FilePath);