Tag Archives: WPF

WPF/MVVM DataGrid with Select All

Introduction

WPF is great to quickly build tools because it’s very versatile. In this article, we’re going to disregard the WPF DataGrid’s row selection functionality, and create a DataGrid that allows (a) selection of individual items using a checkbox, and (b) selection of all/none using a master checkbox:

wpf-dgselectall-finalresult

We’re going to do this using the Model-View-ViewModel approach, which you should be already familiar with (at least in theory) before reading on.

The source code for this article is available at the Gigi Labs BitBucket repository.

Setting up MVVM

After creating a new WPF application, install the MVVM Light Toolkit using NuGet. install the libs-only version to avoid getting a lot of extra junk in your project:

Install-Package MvvmLightLibs

Create a class called MainWindowViewModel, and make it public:

    public class MainWindowViewModel
    {
    }

In MainWindow.xaml.cs (the codebehind file for the main window), set up the view model as the DataContext:

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            this.DataContext = new MainWindowViewModel();
        }
    }

A Model Object

We need to create a data object (Country in this case) whose fields will be displayed in the DataGrid. For this sort of thing, it typically needs to have:

  1. An ID. We won’t use this here, but if your data is coming from a database, you’ll usually need it.
  2. A name. This will be displayed in the DataGrid.
  3. A selection boolean. This will be used to indicate whether the item has been selected or not, and we will bind the checkbox to it.

Create a class called Country. It needs to be public, and it also needs to derive from GalaSoft.MvvmLight.ObservableObject:

    public class Country : ObservableObject

This will allow us to call the handy Set() method which handles all the INotifyPropertyChanged stuff and makes sure that WPF’s data binding engine gets notified that the property has changed, so that it can update the UI:

    public class Country : ObservableObject
    {
        private int id;
        private string name;
        private bool selected;

        public int Id
        {
            get
            {
                return this.id;
            }
            set
            {
                this.Set(() => Id, ref id, value);
            }
        }

        public string Name
        {
            get
            {
                return this.name;
            }
            set
            {
                this.Set(() => Name, ref name, value);
            }
        }

        public bool Selected
        {
            get
            {
                return this.selected;
            }
            set
            {
                this.Set(() => Selected, ref selected, value);
            }
        }

        public Country(int id, string name)
        {
            this.id = id;
            this.name = name;
        }
    }

The need to do the INotifyPropertyChanged bit prevents us from using autoproperties when implementing WPF models (and adds a significant amount of boilerplate), but the MVVM Light Toolkit reduces this overhead as much as possible.

Setting Up the DataGrid

Let’s add a list of countries to our MainWindowViewModel:

    public class MainWindowViewModel : ViewModelBase
    {
        public ObservableCollection<Country> Countries { get; }

        public MainWindowViewModel()
        {
            var countries = new Country[]
            {
                new Country(1, "Japan"),
                new Country(2, "Italy"),
                new Country(3, "England"),
                new Country(4, "Norway"),
                new Country(5, "Poland")
            };

            this.Countries = new ObservableCollection<Country>(countries);
        }
    }

Here, we’re inheriting from GalaSoft’s own ViewModelBase class, which gives us access to various methods we typically need when doing WPF with MVVM (we’ll use a couple of these later). Other than that, we’re simply creating an ObservableCollection of countries. ObservableCollection is great because it automatically notifies the UI that an item has been added or removed. Although it’s not strictly necessary here, it’s quite ubiquitous in WPF code that uses MVVM.

Next, let’s add the actual DataGrid in MainWindow.xaml:

<Window x:Class="WpfDataGridSelectAll.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfDataGridSelectAll"
        mc:Ignorable="d"
        Title="Choose Countries" Height="350" Width="525">
    <DataGrid AutoGenerateColumns="False"
              ItemsSource="{Binding Path=Countries, Mode=OneWay}">
        <DataGrid.Columns>
            <DataGridTemplateColumn>
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <CheckBox HorizontalAlignment="Center"
                                  IsChecked="{Binding Path=Selected,
                                      UpdateSourceTrigger=PropertyChanged}" />
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
            <DataGridTextColumn Header="Country" Binding="{Binding Path=Name}" />
        </DataGrid.Columns>
    </DataGrid>
</Window>

Note that I could have used a DataGridCheckBoxColumn for the checkbox, but I didn’t. That’s because there’s this annoying problem where you need 2 clicks to select a checkbox in a DataGrid (one to give the row focus, and the other to check the checkbox). A simple solution for this issue is to use a DataGridTemplateColumn instead, and set UpdateSourceTrigger=PropertyChanged.

So now we have a simple DataGrid:

wpf-dgselectall-justdatagrid

Basic Select All

Let’s add a checkbox in the header of the checkbox column. This will act as the master checkbox. When you click this, it will toggle all the other checkboxes.

            <DataGridTemplateColumn>
                <DataGridTemplateColumn.Header>
                    <CheckBox IsChecked="{Binding Path=DataContext.AllSelected,
                                   UpdateSourceTrigger=PropertyChanged,
                                   RelativeSource={RelativeSource FindAncestor,
                                       AncestorType={x:Type Window}}}" />
                </DataGridTemplateColumn.Header>

The binding is a little elaborate because it needs to look for the AllSelected property (which we’ll implement next) on the MainWindowViewModel, which is actually the DataContext of the window.

Next, in the MainWindowViewModel, let’s add a property that the above binding will work with:

        private bool allSelected;

        public bool AllSelected
        {
            get
            {
                return this.allSelected;
            }
            set
            {
                this.Set(() => AllSelected, ref allSelected, value);

                foreach (var country in this.Countries)
                    country.Selected = value;
            }
        }

Note how in the setter, we’re doing some extra logic. When we change the checked value of the master checkbox, we go in and change the Selected state of all the countries accordingly.

This is enough to give us a working Select All/None toggle:

wpf-dgselectall-basic

If you click the top checkbox, all the others will be checked. And if you uncheck it, all the others will be unchecked.

Full Select All

What we did in the previous section has a flaw:

wpf-dgselectall-flaw

If you check the master checkbox, but then uncheck one of the other checkboxes, the master checkbox remains checked! And likewise, if start with nothing checked, and check all of them one by one, this is not reflected in the master checkbox.

In order to make this work properly, the individual checkboxes need a way to tell the view model that their state has changed, so that it can update the master checkbox as needed. One way to do this is to have the Country take a function that it will call whenever the selection state changes:

    public class Country : ObservableObject
    {
        private int id;
        private string name;
        private bool selected;
        private Action<bool> onSelectionChanged;

        // ...

        public bool Selected
        {
            get
            {
                return this.selected;
            }
            set
            {
                this.Set(() => Selected, ref selected, value);

                this.onSelectionChanged(value);
            }
        }

        public Country(int id, string name, Action<bool> onSelectionChanged)
        {
            this.id = id;
            this.name = name;
            this.onSelectionChanged = onSelectionChanged;
        }
    }

In the MainWindowViewModel, we now need to update the Country initialisation to pass in a method which we’ll create next:

        public MainWindowViewModel()
        {
            var countries = new Country[]
            {
                new Country(1, "Japan", OnCountrySelectionChanged),
                new Country(2, "Italy", OnCountrySelectionChanged),
                new Country(3, "England", OnCountrySelectionChanged),
                new Country(4, "Norway", OnCountrySelectionChanged),
                new Country(5, "Poland", OnCountrySelectionChanged)
            };

            this.Countries = new ObservableCollection<Country>(countries);
        }

The method that gets called whenever a checkbox changes needs to cater for two edge cases:

  1. Master checkbox is checked (i.e. all are selected), but a checkbox just got unchecked. The master checkbox needs to be unchecked.
  2. Master checkbox is unchecked (i.e. not all are selected), and all checkboxes are now checked. The master checkbox needs to be checked.

Here’s the implementation:

        private void OnCountrySelectionChanged(bool value)
        {
            if (allSelected && !value)
            { // all are selected, and one gets turned off
                allSelected = false;
                RaisePropertyChanged(() => this.AllSelected);
            }
            else if (!allSelected && this.Countries.All(c => c.Selected))
            { // last one off one gets turned on, resulting in all being selected
                allSelected = true;
                RaisePropertyChanged(() => this.AllSelected);
            }
        }

Note how we are not setting the AllSelected property directly, as that would execute the foreach statement that affects the other checkboxes. Instead, we are bypassing this by setting the backing field, and notifying WPF’s data binding engine that it needs to get the latest value for the AllSelected property.

And this gives us a fully working master checkbox:

wpf-dgselectall-finalresult

C# AppSettings: Saving User Preferences in a WPF Browser application

This article was originally postedĀ at Programmer’s Ranch on 23rd March 2014.

Hey Ya! šŸ™‚

In yesterday’s article, “C# AppSettings: Launching Programs and Storing AppSettings“, we learned how you can store application settings in an App.config file so that they can be easily changed without having to recompile the program. This is useful for settings that don’t change very often, but is not the best way to store user preferences.

In today’s article, we will see how we can use a .NET Settings file in order to save user preferences. To do this, we will build a simple WPF browser application* and allow the user to save his homepage.

* For those who already know a little bit about WPF, we’re just going to make a simple application that includes a WebBrowser control – not an XBAP.

So, for starters, create a new WPF application using your favourite IDE. Aside from an App.xaml, you should also have a window – this would be Window1.xaml in SharpDevelop, or MainWindow.xaml in Visual Studio.

Change the window’sĀ Title,Ā WidthĀ andĀ HeightĀ properties to something decent (e.g. width of 800 and height of 600). Then, replace the defaultĀ <Grid>Ā in the window’s XAML with the following:

    <DockPanel>
        <DockPanel LastChildFill="True" DockPanel.Dock="Top">
            <Button Name="GoButton" DockPanel.Dock="Right" Margin="5 5 5 5" Click="Button_Click">Go</Button>
            <Button Name="SaveButton" DockPanel.Dock="Right" Margin="5 5 5 5">Save homepage</Button>
            <TextBox Name="Homepage" DockPanel.Dock="Left" Margin="5 5 5 5" />
        </DockPanel>
        <WebBrowser Name="Browser" VerticalAlignment="Stretch" />
    </DockPanel>

This isn’t a WPF tutorial so don’t worry about the above XAML; you’ll see what it does in a second. Find the window’s codebehind file by expanding your Window1.xaml (or MainWindow.xaml) node in Solution Explorer, and open it:

csbrowser-codebehind

In the window class’s constructor, add the following code afterĀ InitializeComponent():

            string homePageUrl = "http://en.wikipedia.org/wiki/Main_Page";
            this.Homepage.Text = homePageUrl;
            this.Browser.Navigate(homePageUrl);

You can now run the application to see what it looks like:

csbrowser-browser

That was pretty easy! We set up the browser embedded in our window to load Wikipedia by default, and that’s what it did. Now, let’s get our program to actually do something.

In the XAML for the “Go” button, start typing the word “Click”, then press TAB twice. This should generate the following code in your window’s codebehind file (remember, it’s the .xaml.cs file):

        void GoButton_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            throw new NotImplementedException();
        }

Replace the body of this method with the following:

this.Browser.Navigate(this.Homepage.Text);

We can now type in a URL and press the “Go” button to navigate there:

csbrowser-navigate

Now, let’s work on that “Save homepage” button. First, add a button handler as you did before – by starting to type the word “Click” in the XAML for the “Save homepage” button, pressing TAB, selecting “<new event handler>”, and then pressing TAB again. You should have an empty handler similar to the one you had for the “Go” button earlier:

        void SaveButton_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            throw new NotImplementedException();
        }

Next, right click on your project in Solution Explorer, and select Add -> New Item…Ā and add a new Settings file. If you’re using SharpDevelop, you’ll find this under the MiscĀ category:

csbrowser-addsettingsfile

This file opens up a table where you can add settings as you like. Let’s add one for the homepage:

csbrowser-editsettingsfile

You just need to set the name, data type, and default value of the property. The Scope can be either User or Application.Ā This articleĀ at MSDN explains the difference:

Application-scope settings are read only, and can only be changed at design time or by altering the <AssemblyName>.exe.config file in between application sessions. User-scope settings, however, can be written at run time, just as you would change any property value. The new value persists for the duration of the application session. You can persist changes to user settings between application sessions by calling theĀ Settings.SaveĀ method. These settings are saved in the User.config file.

In short, Application-scope settings are pretty similar to what we did yesterday in “C# AppSettings: Launching Programs and Storing AppSettings“, while User-scope settings are ideal for saving user preferences – which is what we want to do now.

In your window’s constructor, you can now load the homepage from your settings. You first need to build your project to allow the IDE to do some magic underneath (otherwise you won’t be able to find the property. Then, you can load the homepage setting like this:

            string homePageUrl = Settings1.Default.HomePage;

The good thing about these kinds of settings are that they are strongly-typed. This means that if you’re loading, for example, an integer, you can just assign it directly to an integer variable without further ado. Using regular AppSettings (see “C# AppSettings: Launching Programs and Storing AppSettings“), on the other hand, you first have to read values into strings and then convert them to the appropriate type.

Saving settings is also pretty straightforward. You assign them using the same notation as above, and thenĀ Save() them so that the settings can be remembered next time you run the application:

        void SaveButton_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            Settings1.Default.HomePage = this.Homepage.Text;
            Settings1.Default.Save();
           
            MessageBox.Show("Settings have been saved", "Homepage update");
        }

So now, we can run our application, enter a new URL in the homepage, and click the “Save homepage” button:

csbrowser-savesettings

…and the next time we run our application, it loads our new homepage by default:

csbrowser-loadsettings

As you can see, the WPF WebBrowser control is actually some version of Internet Explorer – you can see it compared to a REAL browser in a previous screenshot. Still, Internet Explorer can sometimes be useful. To download another browser, for instance. šŸ˜€

Cool. šŸ™‚ In this article, we saw how to use a .NET Settings file to load and save user preferences quickly and easily. We saw this in action by loading and saving the homepage in a simple WPF browser application. Thanks for reading, and see you in time for the next article! šŸ™‚

Security Risk in Binding WPF PasswordBox Password

This article was originally posted here at Programmer’s Ranch with the title “C# WPF/MVVM: Why You Shouldn’t Bind PasswordBox Password”, on 4th October 2014.

Hi! šŸ™‚

In WPF circles, theĀ PasswordBoxĀ control has generated quite a bit of discussion. The thing is that you can access the password entered by the user using the PasswordĀ property, but it’s not a dependency property, and MVVM purists don’t like the fact that they can’t bind it to their ViewModel.

In this article, I’m going to show how the password can be bound in the ViewModel despite this limitation. And I’m also going to show you why it’s a very bad idea to do this. This article is a little advanced in nature, and assumes you’re familiar with WPF and MVVM.

Right, so let’s set up something we can work with. Create a new WPF application, and then add a new class called MainWindowViewModel. In your MainWindow‘s codebehind (i.e. MainWindow.xaml.cs), set up your window’s DataContext by adding the following line at the end of your constructor:

            this.DataContext = new MainWindowViewModel();

Right, now let’s add a couple of properties to our MainWindowViewModel that we’ll want to bind to:

        public string Username { get; set; }
        public string Password { get; set; }

Now we can build our form by editing the XAML in MainWindow.xaml. Let’s go with this (just make sure the namespace matches what you have):

<Window x:Class="CsWpfMvvmPasswordBox.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Login"
        Height="120"
        Width="325">
    <Grid>

        <Grid.RowDefinitions>
            <RowDefinition Height="20" />
            <RowDefinition Height="20" />
            <RowDefinition Height="30" />
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="90" />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>

        <TextBlock Text="Username:"
            Grid.Row="0"
            Grid.Column="0"
            Margin="2" />
        <TextBox Text="{Binding Path=Username}"
            Grid.Row="0"
            Grid.Column="1"
            Margin="2" />

        <TextBlock Text="Password:"
            Grid.Row="1"
            Grid.Column="0"
            Margin="2" />
        <PasswordBox Password="{Binding Path=Password}"
            Grid.Row="1"
            Grid.Column="1"
            Margin="2" />

        <Button Content="Login"
            Grid.Row="2"
            Grid.Column="1"
            HorizontalAlignment="Right"
            Width="100"
            Margin="2" />
    </Grid>
</Window>

Now, you’ll notice right away that something’s wrong when you see the blue squiggly line at the password binding:

wpf-bindpasswordbox-cantbind

Oh no! What are we going to do now? If we can’t bind the password, and have to somehow retrieve it from the control, then we’ll break the MVVM pattern, right? And we MVVM knights-in-shining-armour can’t afford to deviate from the path of light that is MVVM. You see, the Password property can’t be bound specifically because it shouldn’t, but let’s say that we’re like most other developers and we’re so blinded by this MVVM dogma that we don’t care about the security concerns and we want an MVVM-friendly solution.

Well, no problem! It turns out that there actually isĀ an MVVM-friendly way to bind the password – see theĀ PasswordBoxAssistantĀ andĀ PasswordHelperĀ implementations. To get up and running, let’s add a new PasswordBoxHelperĀ class to our project, and add the implementation from the second link:

    public static class PasswordHelper
    {
        public static readonly DependencyProperty PasswordProperty =
            DependencyProperty.RegisterAttached("Password",
            typeof(string), typeof(PasswordHelper),
            new FrameworkPropertyMetadata(string.Empty, OnPasswordPropertyChanged));

        public static readonly DependencyProperty AttachProperty =
            DependencyProperty.RegisterAttached("Attach",
            typeof(bool), typeof(PasswordHelper), new PropertyMetadata(false, Attach));

        private static readonly DependencyProperty IsUpdatingProperty =
            DependencyProperty.RegisterAttached("IsUpdating", typeof(bool),
            typeof(PasswordHelper));


        public static void SetAttach(DependencyObject dp, bool value)
        {
            dp.SetValue(AttachProperty, value);
        }

        public static bool GetAttach(DependencyObject dp)
        {
            return (bool)dp.GetValue(AttachProperty);
        }

        public static string GetPassword(DependencyObject dp)
        {
            return (string)dp.GetValue(PasswordProperty);
        }

        public static void SetPassword(DependencyObject dp, string value)
        {
            dp.SetValue(PasswordProperty, value);
        }

        private static bool GetIsUpdating(DependencyObject dp)
        {
            return (bool)dp.GetValue(IsUpdatingProperty);
        }

        private static void SetIsUpdating(DependencyObject dp, bool value)
        {
            dp.SetValue(IsUpdatingProperty, value);
        }

        private static void OnPasswordPropertyChanged(DependencyObject sender,
            DependencyPropertyChangedEventArgs e)
        {
            PasswordBox passwordBox = sender as PasswordBox;
            passwordBox.PasswordChanged -= PasswordChanged;

            if (!(bool)GetIsUpdating(passwordBox))
            {
                passwordBox.Password = (string)e.NewValue;
            }
            passwordBox.PasswordChanged += PasswordChanged;
        }

        private static void Attach(DependencyObject sender,
            DependencyPropertyChangedEventArgs e)
        {
            PasswordBox passwordBox = sender as PasswordBox;

            if (passwordBox == null)
                return;

            if ((bool)e.OldValue)
            {
                passwordBox.PasswordChanged -= PasswordChanged;
            }

            if ((bool)e.NewValue)
            {
                passwordBox.PasswordChanged += PasswordChanged;
            }
        }

        private static void PasswordChanged(object sender, RoutedEventArgs e)
        {
            PasswordBox passwordBox = sender as PasswordBox;
            SetIsUpdating(passwordBox, true);
            SetPassword(passwordBox, passwordBox.Password);
            SetIsUpdating(passwordBox, false);
        }
    }

You will also need to add the followingĀ usings at the top:

using System.Windows;
using System.Windows.Controls;

Now, let’s fix our Password binding. First, add the following attribute to the Window declaration in the XAML so that we can access our project’s classes (adjust namespace as needed):

        xmlns:local="clr-namespace:CsWpfMvvmPasswordBox"

Then update the PasswordBox declaration to use the PasswordBoxHelper as follows:

        <PasswordBox local:PasswordHelper.Attach="True"
            local:PasswordHelper.Password="{Binding Path=Password}"
            Grid.Row="1"
            Grid.Column="1"
            Margin="2" />

That did it! The project now compiles.

Now, let’s see why what we have done is a very stupid thing to do. To do this, we’re going to need this WPF utility calledĀ Snoop, so go over to their website, download it, and install it using the .msi file.

Run Snoop. All you’ll see is a thin bar with a few buttons. On the right hand side, there is a button that looks like a circle (in fact it’s supposed to be crosshairs). If you hover over it, it will explain how to use it:

wpf-bindpasswordbox-snoop1

Run the WPF application we just developed. Enter something into the PasswordBox, but shhhh! Don’t tell anyone what you wrote there! šŸ™‚

Next, drag those crosshairs from Snoop onto the WPF window:

wpf-bindpasswordbox-snoop2

When you let go, a window opens. In the treeview to the left, you can navigate through the mounds of crap that internally make up our simple application. When you find the PasswordBox, you’ll also find the PasswordHelper:

wpf-bindpasswordbox-snoop3

…and as you can see, the PasswordHelper keeps the password exposed in memory so anyone who knows what he’s doing can gain access to it. With a program like Snoop, anyone can access passwords that are bound.

There are a couple of lessons to take from this.

First, don’t ever bind passwords in WPF. There are other alternatives you can use, such asĀ passing your entire PasswordBox control as a binding parameterĀ – although this sounds extremely stupid, it’s a lot more secure than binding passwords. And arguably, it doesn’t break the MVVM pattern.

Secondly, don’t be so religious about so-called best practices such as MVVM. Ultimately they are guidelines, and there are many cases such as this where there are more important things to consider (in this case, security). For something as simple as a login window, it’s much more practical to just do without MVVM and do everything in the codebehind. It isn’t going to affect the scalability, maintainability, robustness, [insert architectural buzz-word here], etc of your application if you make an exception that is rational.

Before ending this article, I would like to thank the person who postedĀ this answerĀ to one of my questions on Stack Overflow. That answer helped me understand the dangers of binding passwords, and provided the inspiration for this article. As further reading, you might also want to readĀ this other questionĀ (and its answer)Ā which deals with the security of processing passwords in memory in general (not just data binding).

That’s all for today. Happy coding! šŸ™‚