Base WPF Window Functionality for Data Entry






4.08/5 (7 votes)
Controls verifying user input and reporting automatically to host window if data has been changed and if the required data is entered
Table of Contents
- Introduction
- User Experience
- Using the Code
- What Happens Under the Cover
- Getting WpfWindowsLib
- History
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
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?
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:
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);
}
}
- During initialisation, the
ICheck
control searches the window it is placed on. If that window inherits fromCheckedWindow
, it registers with that window. During that registration, theCheckedWindow
subscribes to theHasChangedEvent
andIsAvailableEvent
event of the control. - When the user then changes some data in the control and this leads to a change of
HasChanged
orIsAvailable
, the control raises the appropriate event, which alertsCheckedWindow
.CheckedWindow
queries all registered controls to evaluate if its ownHasICheckChanged
orIsAvailable
properties need to change and then callsOnICheckChanged
andOnIsAvailableChanged
, which gives the inheriting window the chance, to enable or disable the Save button accordingly. - 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.
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 solutionsSamples
: WPF Core application showing allWpfWindowsLib
controlsWpfWindowsLibTest
: with fewWpfWindowsLib
unit tests
Recommended Reading
- Email Address Validation Explained in Detail (WpfWindowsLib)
- International Phone Number Validation Explained in Detail(WpfWindowsLib)
- Guide to WPF DataGrid Formatting Using Bindings
History
- 20th February, 2020: Initial version