WPF Bootcamp
Validation and User Input
A polished WPF app does not just collect input. It guides the user toward valid input, explains errors clearly, and keeps commands in sync with the current state of the form.
Validation is part of interaction design, not just an exception that happens late.
What you'll learn
- Where validation can live: view model, binding rules, or domain layer.
- How binding errors surface on controls and how commands react to invalid state.
- How to design forms that feel responsive instead of hostile.
- How to separate raw user input, transient edit state, and committed valid state.
<TextBox>
<TextBox.Text>
<Binding Path="Email"
UpdateSourceTrigger="PropertyChanged"
ValidatesOnDataErrors="True" />
</TextBox.Text>
</TextBox>
That binding is not only copying text. It is participating in a validation pipeline that can decide whether the user's current input is acceptable and how the UI should respond if it is not.
The mental model in one sentence
Validation in WPF is a conversation between the binding layer, the view model or domain rules, and the visual layer that communicates problems back to the user.
Validation is not only technical
A field may be invalid according to a rule, but the UX still determines whether the user understands what to do next.
Validation is not only visual
Red borders without good messages or command logic do not produce a usable form.
Where validation can live
WPF supports several validation layers, and they solve slightly different problems.
- View model validation: useful for screen state and rules close to the editing workflow.
- Binding validation rules: useful for conversion or binding-specific checks.
- Domain validation: useful for business rules that must hold even outside the current screen.
The strongest pattern is usually to validate as close to the real rule as possible, then surface the result through binding and command state instead of scattering ad hoc checks across controls.
Real-time validation vs commit-time validation
Not every form should validate in the same rhythm. Some fields benefit from immediate feedback while others feel better when validated on focus loss or on submit.
Validate while typing when
The rule is simple, cheap, and helpful to see immediately, such as required fields or obvious formatting problems.
Validate on commit when
The rule is expensive, noisy, or would punish the user for partially typed input.
<Binding Path="Email"
UpdateSourceTrigger="PropertyChanged"
ValidatesOnDataErrors="True" />
UpdateSourceTrigger strongly affects the feel of validation because it determines when the edited value reaches the source and can therefore be checked.
Error surfacing should be local and understandable
Users need to know which field has a problem, why it is a problem, and what they should do about it.
- Show the error near the field whenever possible.
- Use explanatory text, not just color or an icon.
- Prefer language the user can act on rather than internal rule wording.
A red border is a useful signal, but it is rarely enough by itself.
Commands and validation should cooperate
Validation should not live in isolation. If the current form state is invalid, command availability often needs to reflect that.
private bool CanSave()
{
return !HasErrors;
}
That keeps the UI honest. The user sees that the form is not currently submittable, and the save action does not need to rediscover the obvious state too late.
Practical takeaway: disable commands only when the user truly cannot proceed. Over-disabling can hide useful workflows and make forms feel uncooperative.
Separate transient typing state from committed valid state when needed
Some workflows should not immediately push every keystroke into durable domain state. This is especially true when a field can be temporarily invalid while the user is still editing.
In those cases, it can be useful to keep temporary screen-edit state in the view model, then commit it to the model or service layer only when the form is valid enough to proceed.
This avoids corrupting domain objects with half-typed input while still letting the screen show responsive validation feedback.
Design principles
- Validate as close to the real rule as possible.
- Show errors near the field and in language the user can act on.
- Disable commands only when the user truly cannot proceed.
- Separate transient typing state from committed domain updates when the workflow needs it.
A worked form example
<StackPanel>
<TextBox>
<TextBox.Text>
<Binding Path="Email"
UpdateSourceTrigger="PropertyChanged"
ValidatesOnDataErrors="True" />
</TextBox.Text>
</TextBox>
<TextBlock Text="{Binding EmailErrorMessage}" />
<Button Content="Save" Command="{Binding SaveCommand}" />
</StackPanel>
- The user types into the email field.
- The binding pushes text into the view model as the user types.
- The validation layer checks whether the email is acceptable.
- The UI surfaces the problem near the field if validation fails.
- The save command reevaluates whether execution is allowed.
- Once the input is valid, the error clears and the command can proceed.
This is the full interaction loop: input, validation, user feedback, and command availability all reinforce each other.
Common mistakes
- Only validating on submit, which leaves the UI feeling unresponsive and ambiguous.
- Embedding domain rules in the view without any reusable validation layer.
- Using error visuals without clear explanatory text.
- Treating invalid intermediate typing states as if they were final committed values.
- Letting commands ignore invalid state until the last possible moment.
InkkSlinger parity note: The binding and validation primitives in this repo are WPF-inspired, which means the same broad guidance applies: validation should flow through the binding surface and command state rather than via manual control mutation whenever possible.
Next, zoom out from one screen and learn how WPF applications compose multiple views, windows, and shared services.