RunicArtifex.ReactiveUI.Validation 9.0.0

dotnet add package RunicArtifex.ReactiveUI.Validation --version 9.0.0
                    
NuGet\Install-Package RunicArtifex.ReactiveUI.Validation -Version 9.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="RunicArtifex.ReactiveUI.Validation" Version="9.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="RunicArtifex.ReactiveUI.Validation" Version="9.0.0" />
                    
Directory.Packages.props
<PackageReference Include="RunicArtifex.ReactiveUI.Validation" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add RunicArtifex.ReactiveUI.Validation --version 9.0.0
                    
#r "nuget: RunicArtifex.ReactiveUI.Validation, 9.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package RunicArtifex.ReactiveUI.Validation@9.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=RunicArtifex.ReactiveUI.Validation&version=9.0.0
                    
Install as a Cake Addin
#tool nuget:?package=RunicArtifex.ReactiveUI.Validation&version=9.0.0
                    
Install as a Cake Tool

Runic ReactiveUI.Validation (.NET 10)

This Runic-Artifex fork of upstream ReactiveUI.Validation uses ReactiveUI 26.0.1 with the released 10.0.0 RunicArtifex.DynamicData packages from NuGet.org. It ships two core NuGet packages:

Package ID Namespace root Dependencies
RunicArtifex.ReactiveUI.Validation ReactiveUI.Validation ReactiveUI, RunicArtifex.DynamicData
RunicArtifex.ReactiveUI.Validation.Reactive ReactiveUI.Validation.Reactive ReactiveUI.Reactive, RunicArtifex.DynamicData.Reactive

Both target .NET 10. Use the flavor that matches your ReactiveUI package; the Reactive flavor's validation collection uses DynamicData.Reactive types. Keep one flavor per application and replace upstream Validation and DynamicData references with the matching RunicArtifex.* IDs. The namespaces and assembly names remain ReactiveUI.Validation and ReactiveUI.Validation.Reactive. The original MIT license and authorship remain.

Install both packages and their dependencies from nuget.org; release notes are on the GitHub releases page. Earlier releases were published only as GitHub release assets, under the IDs Runic.ReactiveUI.Validation and Runic.ReactiveUI.Validation.Reactive; those assets stay as they are, and nuget.org has only the RunicArtifex.* IDs. See CONTRIBUTING to build and test, NativeAOT and generators for trimming/AOT, the maintenance policy and fork difference register for fork policy, and the upstream assessment for upstream issues and PRs with Runic dispositions. AndroidX and platform samples are outside core CI and releases. This fork will not be proposed upstream.

Generated validation API (unreleased)

On the maintained branch, inline-lambda ValidationRule, BindValidation, BindValidationContext, BindValidationState and ValidationBinding.For* calls are intercepted by a Validation source generator embedded in each core package, producing direct typed getters, notifications and setters that work under trimming and NativeAOT. Consumers keep the package's analyzer and buildTransitive assets and recompile their call sites. Typed selectors, targets, storage cells/lenses and finite owner-scoped plan registration cover cases the generator cannot handle automatically (silent fields, runtime selectors, precompiled callers, immutable targets). Unregistered normal calls fail actionably; there is no reflection fallback. Normal property text bindings expose the actual initial state.

ValidationRuleUnsafe, BindValidationUnsafe, BindValidationContextUnsafe and BindValidationStateUnsafe keep reflected runtime expressions and their trimming warnings, plus the legacy empty-list prelude. Supplied-observable rule overloads and the explicit observable APIs remain available. See the capability reference, migration guide and design.


RunicArtifex.ReactiveUI.Validation on nuget.org · RunicArtifex.ReactiveUI.Validation.Reactive on nuget.org · Release notes

The upstream usage guide and contributor history below are retained for reference. Its NuGet badges link to the upstream distribution.

NuGet Downloads Build Code Coverage License Slack Good First Issues Stars

<a href="https://github.com/reactiveui/ReactiveUI.Validation"> <img width="140" heigth="140" src="https://github.com/reactiveui/ReactiveUI.Validation/blob/main/media/logo.png"> </a>

ReactiveUI.Validation

Validation for ReactiveUI based solutions, functioning in a reactive way.

Read this in other languages: Español.

Core Team

<table> <tbody> <tr> <td align="center" valign="top"> <img width="100" height="100" src="https://github.com/ChrisPulman.png?s=150"> <br> <a href="https://github.com/ChrisPulman">Chris Pulman</a> <p>London, UK</p> </td> <td align="center" valign="top"> <img width="100" height="100" src="https://github.com/glennawatson.png?s=150"> <br> <a href="https://github.com/glennawatson">Glenn Watson</a> <p>Melbourne, Australia</p> </td> </tr> </tbody> </table>

Alumni & History

ReactiveUI.Validation was originally developed by @jcmm33 as Vistian.Reactive.Validation, and then refactored and updated by Àlex Martínez Morón and the ReactiveUI community.

Runic support and packages

The two packages listed above support .NET 10, including platform-specific .NET 10 applications. AndroidX source projects are retained for separate workload builds; they are not included in the core release assets. See CONTRIBUTING.

How to Use

  • For ViewModels which need validation, implement IValidatableViewModel.
  • Add validation rules to the ViewModel using the ValidationRule extension methods.
  • Bind to the validation rules in the View via BindValidation or INotifyDataErrorInfo.

Example

  1. Decorate existing ViewModel with IValidatableViewModel, which has a single member, ValidationContext. The ValidationContext contains all of the functionality surrounding the validation of the ViewModel. Most access to the specification of validation rules is performed through extension methods on the IValidatableViewModel interface. Then, add validation to the ViewModel.
using ReactiveUI.Validation.Extensions;

public class SampleViewModel : ReactiveObject, IValidatableViewModel
{
    public SampleViewModel()
    {
        // Creates the validation for the Name property.
        this.ValidationRule(
            viewModel => viewModel.Name,
            name => !string.IsNullOrWhiteSpace(name),
            "You must specify a valid name");
    }

    public ValidationContext ValidationContext { get; } = new ValidationContext();

    private string _name;
    public string Name
    {
        get => _name;
        set => this.RaiseAndSetIfChanged(ref _name, value);
    }
}

For more complex validation scenarios there are several more overloads of the ValidationRule extension method that accept observables. These allow validation to occur asynchronously, and allows complex chains of observables to be combined to produce validation results.

The simplest accepts an IObservable<bool> where the observed boolean indicates whether the ValidationRule is valid or not. The overload accepts a message which is used when the observable produces a false (invalid) result.

IObservable<bool> passwordsObservable =
    this.WhenAnyValue(
        x => x.Password,
        x => x.ConfirmPassword,
        (password, confirmation) => password == confirmation);

this.ValidationRule(
    vm => vm.ConfirmPassword,
    passwordsObservable,
    "Passwords must match.");

Any existing observables can be used to drive a ValidationRule using the extension method overload that accepts an arbitrary IObservable<TState> streams of events. The overload accepts a custom validation function that is supplied with the latest TState, and a custom error message function, responsible for formatting the latest TState object. The syntax for this looks as follows:

// IObservable<{ Password, Confirmation }>
var passwordsObservable =
    this.WhenAnyValue(
        x => x.Password,
        x => x.ConfirmPassword,
        (password, confirmation) =>
            new { Password = password, Confirmation = confirmation });

this.ValidationRule(
    vm => vm.ConfirmPassword,
    passwordsObservable,
    state => state.Password == state.Confirmation,
    state => $"Passwords must match: {state.Password} != {state.Confirmation}");

Note The function to extract a message (messageFunc) is only invoked if the function to establish validity (isValidFunc) returns false, otherwise the message is set to string.Empty.

Finally, you can directly supply an observable that streams any object (or struct) that implements IValidationState; or you can use the ValidationState base class which already implements the interface. As the resulting object is stored directly against the context without further transformation, this can be the most performant approach:

IObservable<IValidationState> usernameNotEmpty =
    this.WhenAnyValue(x => x.UserName)
        .Select(name => string.IsNullOrEmpty(name)
            ? new ValidationState(false, "The username must not be empty")
            : ValidationState.Valid);

this.ValidationRule(vm => vm.UserName, usernameNotEmpty);

Note As a valid ValidationState does not really require a message, there is a singleton ValidationState.Valid property that you are encouraged to use to indicate a valid state whenever possible, to reduce memory allocations.

  1. Add validation presentation to the View.
using ReactiveUI.Validation.Extensions;

public class SampleView : ReactiveContentPage<SampleViewModel>
{
    public SampleView()
    {
        InitializeComponent();
        this.WhenActivated(disposables =>
        {
            this.Bind(ViewModel, vm => vm.Name, view => view.Name.Text)
                .DisposeWith(disposables);

            // Bind any validations that reference the Name property
            // to the text of the NameError UI control.
            this.BindValidation(ViewModel, vm => vm.Name, view => view.NameError.Text)
                .DisposeWith(disposables);

            // Bind any validations attached to this particular view model
            // to the text of the FormErrors UI control.
            this.BindValidation(ViewModel, view => view.FormErrors.Text)
                .DisposeWith(disposables);
        });
    }
}

Example with Android Extensions

There are extensions methods for Android and its Material design control TextInputLayout. These extensions use internally the Error property from the TextInputLayout control, allowing you to implement a fully native behavior to showing validation errors. To use these extensions you must import ReactiveUI.Validation.Extensions and install ReactiveUI.Validation.AndroidX:

dotnet add package ReactiveUI.Validation.AndroidX

<img src="https://user-images.githubusercontent.com/6759207/96716730-15729480-13ae-11eb-928e-7e408b7ffac4.png" width="400" />

// This using directive makes Android-specific extensions available.
using ReactiveUI.Validation.Extensions;

public class SignUpActivity : ReactiveAppCompatActivity<SignUpViewModel>
{
    // The Android native text boxes declared in an .axml file.
    public TextInputEditText Password { get; set; }
    public TextInputEditText ConfirmPassword { get; set; }

    // The layouts wrapping the text boxes declared in an .axml file.
    public TextInputLayout PasswordField { get; set; }
    public TextInputLayout ConfirmPasswordField { get; set; }

    protected override void OnCreate (Bundle bundle)
    {
        base.OnCreate(bundle);
        SetContentView(Resource.Layout.Main);

        // The WireUpControls method is a magic ReactiveUI utility method for Android, see:
        // https://www.reactiveui.net/docs/handbook/data-binding/xamarin-android/wire-up-controls
        this.WireUpControls();
        this.Bind(ViewModel, x => x.Password, x => x.Password.Text);
        this.Bind(ViewModel, x => x.ConfirmPassword, x => x.ConfirmPassword.Text);

        // Bind any validations which reference the Password property
        // to the Error property of the TextInputLayout control.
        this.BindValidation(ViewModel, x => x.Password, PasswordField);
        this.BindValidation(ViewModel, x => x.ConfirmPassword, ConfirmPasswordField);
    }
}

INotifyDataErrorInfo Support

For those platforms that support the INotifyDataErrorInfo interface, ReactiveUI.Validation provides a helper base class named ReactiveValidationObject. The helper class implements both the IValidatableViewModel interface and the INotifyDataErrorInfo interface. It listens to any changes in the ValidationContext and invokes INotifyDataErrorInfo events.

<img width="400" src="https://user-images.githubusercontent.com/6759207/96717163-bbbe9a00-13ae-11eb-8c54-89cd339cbd5c.png">

using ReactiveUI.Validation.Extensions;

public class SampleViewModel : ReactiveValidationObject
{
    public SampleViewModel()
    {
        this.ValidationRule(
            viewModel => viewModel.Name,
            name => !string.IsNullOrWhiteSpace(name),
            "Name shouldn't be null or white space.");
    }

    private string _name = string.Empty;
    public string Name
    {
        get => _name;
        set => this.RaiseAndSetIfChanged(ref _name, value);
    }
}

Note Keep in mind that INotifyDataErrorInfo is only supported via XAML binding. ReactiveUI binding doesn't use the inbuilt classes of WPF.

When using a ValidationRule overload that accepts an observable, please remember to supply the property which the validation rule is targeting as the first argument. Otherwise it is not possible for INotifyDataErrorInfo to conclude which property the error message is for.

this.ValidationRule(
    vm => vm.ConfirmPassword,
    passwordsObservable,
    "Passwords must match.");

Custom Formatters

You can pass an instance of IValidationTextFormatter<T> to a call to BindValidation if you'd like to override the default SingleLineFormatter used in the validation library. The SingleLineFormatter accepts a separator char and uses whitespace by default, so the code snippet below shows how to use a non-default separator char:

// This formatter is based on the default SingleLineFormatter but uses a custom separator char.
var formatter = new SingleLineFormatter(Environment.NewLine);
this.BindValidation(ViewModel, x => x.ErrorLabel.Text, formatter)
    .DisposeWith(disposables);

The simplest possible custom IValidationTextFormatter<TOut> implementation may look like this one.

private class ConstFormatter : IValidationTextFormatter<string>
{
    private readonly string _text;

    public ConstFormatter(string text = "The input is invalid.") => _text = text;

    public string Format(ValidationText validationText) => _text;
}

// This formatter is based on a custom IValidationTextFormatter implementation.
var formatter = new ConstFormatter("The input is invalid.");
this.BindValidation(ViewModel, x => x.ErrorLabel.Text, formatter)
    .DisposeWith(disposables);

If you'd like to override the IValidationTextFormatter<string> used in ReactiveUI.Validation by default, register an instance of IValidationTextFormatter<string> into Locator.CurrentMutable before your app starts. This could be useful in cases when your app needs localization and you wish to pass message keys instead of messages to ValidationRule calls.

// Register a singleton instance of IValidationTextFormatter<string> into Splat.Locator.
Locator.CurrentMutable.RegisterConstant(new CustomFormatter(), typeof(IValidationTextFormatter<string>));

Capabilities

In essence, ReactiveUI.Validation is a relatively simple model of the ValidationContext containing a list of IValidationComponent instances. An IValidationComponent provides an observable of IValidationState. Whenever validation state changes (either a transition of validity) or ValidationText changes, then a new value is pushed out.

  1. Rules can be composed of single or multiple properties along with more generic Observables.
  2. Validation text can encapsulate both valid and invalid states.
  3. Binding can occur to either a View or an action.
  4. Validation text can reference either the ViewModel or properties which comprise the validation rule e.g. include text entered as part of validation message.
  5. Validation text output can be adjusted using custom formatters, not only allowing for single & multiline output but also for platforms like Android it should be possible to achieve richer renderings i.e. Bold/italics.

Contribute

ReactiveUI.Validation is developed under an OSI-approved open source license, making it freely usable and distributable, even for commercial use. We love the people who are involved in this project, and we'd love to have you on board, especially if you are just getting started or have never contributed to open-source before.

So here's to you, lovely person who wants to join us — this is how you can support us:

Sponsors

JetBrains gives ReactiveUI's maintainers licences for its tools through its open source support programme. Anthropic supports them with Claude through Claude for Open Source. OpenAI supports them with Codex through Codex for Open Source.

JetBrains Claude by Anthropic OpenAI

See our sponsors for more information. JetBrains, Claude, Anthropic, OpenAI and Codex names and logos are trademarks of their respective owners.

Code released under the MIT license.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
9.0.0 3,700 10/30/2026
9.0.0-runic.9 6,477 10/21/2026