Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Base WPF Window Functionality for Data Entry

0.00/5 (No votes)
25 Mar 2020 1  
Controls verifying user input and reporting automatically to host window if data has been changed and if the required data is entered
WpfWindowsLib eliminates a lot of boiler plate code needed for data entry windows. The controls verify user input (numbers, email address, phone number, ...) and inform the host window if any data has changed, i.e., saving is needed before the user can close the window. The user can only save the data once all required data is entered. Most of that functionality gets provided by just placing the controls on the window.

Table of Contents

Introduction

In most programs, there are some windows where the user has to enter some data, which the controls should validate. Only once all required data is entered, can the user save it. If he has changed some data but not saved yet, he gets alerted that he might lose some data when he closes the window. Wouldn't it be nice if all that functionality gets added automatically to all your windows without you programming much?

WpfWindowsLib provides this functionality. This article describes its functionality and how to use it. WpfWindowsLib is written for .NET Core 3.1 and higher.

User Experience

Image 1

This might not be the most beautiful window you ever see, but the idea here is to show systematically how the various controls are displayed to the user in their different states. In every row, the same control type gets displayed 3 times. In the first column, each control is empty. In the second column, the control is also empty, but the user has to enter some data before he can press the Save button. In the third column, the controls have some initial data.

The user has now to fill in at least all the required fields. Only then, the Save button gets enabled. Once he has pressed the Save button, it gets disabled again. If the user then changes any data, the Save button is enabled again. An enabled Save button tells the user that he has changed some data.

What happens when the user tries to close the window before saving the changes?

Image 2

He gets a warning message and the window shows him which data he has changed but not saved yet. He can then decide if he wants to close the window and discard the changes or if he wants to continue the data entry and possibly save the changes.

Using the Code

You can get all this functionality with hardly any coding. The WpfWindowsLib library provides controls which:

  • know when their data has changed
  • know when their data has been unchanged (user undid his change)
  • know when a "required" control is lacking data
  • know when a "required" control has data
  • automatically find the Window they are in and inform the Window about each state change

That window has to inherit from CheckedWindow in the WpfWindowsLib.

<wwl:CheckedWindow x:Class="Samples.SampleWindow"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:wwl="clr-namespace:WpfWindowsLib;assembly=WpfWindowsLib">
  <StackPanel>
    <wwl:CheckedTextBox x:Name="TestCheckedTextBox" MinWidth="100" 

                        MaxLength="20" IsRequired="True"/>
    <Button x:Name="SaveButton" Content="_Save"/>
  </StackPanel>
</wwl:CheckedWindow>

CheckedTextBox inherits from TextBox, adds the ICheck functionality (see explanation below) and an IsRequired property. When this is set to true, the user has to provide a value (i.e., Text.Length>0) before the Save button gets available:

Image 3

As in XAML, also in the code behind, the window has to inherit from CheckedWindow:

using System.Windows;
using WpfWindowsLib;

namespace Samples {
  public partial class SampleWindow: CheckedWindow {
    public SampleWindow() {
      InitializeComponent();

      //write some code here to display data coming from a database, etc.
      TestCheckedTextBox.Text = database.Read(...);
      SaveButton.Click += saveButton_Click;
      updateSaveButtonIsEnabled();
    }

    private void saveButton_Click(object sender, RoutedEventArgs e) {
      //write some code here to save the data the user has entered
      database.Write(..., TestCheckedTextBox.Text);
      Close();
    }

    private void updateSaveButtonIsEnabled() {
      SaveButton.IsEnabled = HasICheckChanged && IsAvailable;
    }

    protected override void OnICheckChanged() {
      updateSaveButtonIsEnabled();
    }

    protected override void OnIsAvailableChanged() {
      updateSaveButtonIsEnabled();
    }
  }
}

Only very little code needs to get added to that window:

Save Button

There are no requirements how the window has to look like. But most likely, there will be a Save button. This button is enabled, when some data has changed (=HasICheckChanged ) and all required data is entered (=IsAvailable).

Calling updateSaveButtonIsEnabled()

HasICheckChanged and IsAvailable are properties of CheckedWindow. If they change, CheckedWindow calls OnICheckChanged() or OnIsAvailableChanged(), which need to be overridden to update the Save button state.

What Happens Under the Cover

The controls used need to provide the functionality of the ICHeck interface. The WpfWindowsLib provides the following controls:

  • AutoCompleteBox
  • CheckBox
  • ComboBox
  • DatePicker
  • DecimalTextBox
  • EmailTextBox
  • IntegerTextBox
  • PhoneTextBox
  • TextBox

One is not limited to just these controls, but can inherit from any existing control and add an IChecker, which implements the ICheck interface functionality:

namespace WpfWindowsLib {

  public interface ICheck {

    /// <summary>
    /// Has the user changed the initial value of the control ?
    /// </summary>
    bool HasChanged { get; }

    /// <summary>
    /// Needs the user to change the initial value of the control ?
    /// </summary>
    bool IsRequired { get; }

    /// <summary>
    /// Has the user changed the initial value of the required control ?
    /// </summary>
    bool IsAvailable { get; }

    /// <summary>
    /// Raised when the user changes the initial value of the control 
    /// or when the user undoes any change and
    /// enters the initial value again.
    /// </summary>
    event Action  HasChangedEvent;

    /// <summary>
    /// Raised when the user changes the initial value of the required value control 
    /// or when the user undoes 
    /// any change and enters the initial value again.
    /// </summary>
    event Action  IsAvailableEvent;

    /// <summary>
    /// Tells the control to use the present value as initial value.
    /// </summary>
    void ResetHasChanged();

    /// <summary>
    /// Changes the background color of the control if its value is now 
    /// different than the initial value 
    /// and isChanged is true. If isChanged is false, the background color 
    /// gets displayed from when the
    /// control got initialised.
    /// </summary>
    /// <param name="isChanged"></param>
    void ShowChanged(bool isChanged);
  }
}
  1. During initialisation, the ICheck control searches the window it is placed on. If that window inherits from CheckedWindow, it registers with that window. During that registration, the CheckedWindow subscribes to the HasChangedEvent and IsAvailableEvent event of the control.
  2. When the user then changes some data in the control and this leads to a change of HasChanged or IsAvailable, the control raises the appropriate event, which alerts CheckedWindow. CheckedWindow queries all registered controls to evaluate if its own HasICheckChanged or IsAvailable properties need to change and then calls OnICheckChanged and OnIsAvailableChanged, which gives the inheriting window the chance, to enable or disable the Save button accordingly.
  3. When the user tries to close the window, CheckedWindow checks if any control has unsaved data. If so, it marks those controls so the user can see what is not saved yet. CheckedWindow then asks the user if he really wants to close the window and lose the entered data.

Image 4

Getting WpfWindowsLib

The latest version is available from Github: https://github.com/PeterHuberSg/WpfWindowsLib.

Download or clone everything to your PC, which gives you a solution WpfWindowsLib with the following projects:

  • WpfWindowsLib: (.Dll) to be referenced from your other solutions
  • Samples: WPF Core application showing all WpfWindowsLib controls
  • WpfWindowsLibTest: with few WpfWindowsLib unit tests

Recommended Reading

History

  • 20th February, 2020: Initial version

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here