{"id":21101364,"url":"https://github.com/windows-xaml/template10.validation","last_synced_at":"2025-05-16T18:34:33.927Z","repository":{"id":144134458,"uuid":"67647455","full_name":"Windows-XAML/Template10.Validation","owner":"Windows-XAML","description":null,"archived":false,"fork":false,"pushed_at":"2020-01-02T16:20:45.000Z","size":1144,"stargazers_count":45,"open_issues_count":0,"forks_count":9,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-11-03T09:32:37.137Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Windows-XAML.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2016-09-07T22:14:16.000Z","updated_at":"2023-12-05T03:45:43.000Z","dependencies_parsed_at":null,"dependency_job_id":"3d3ae6d8-fd98-4d28-9d9f-f5dbdf453713","html_url":"https://github.com/Windows-XAML/Template10.Validation","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Windows-XAML%2FTemplate10.Validation","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Windows-XAML%2FTemplate10.Validation/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Windows-XAML%2FTemplate10.Validation/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Windows-XAML%2FTemplate10.Validation/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Windows-XAML","download_url":"https://codeload.github.com/Windows-XAML/Template10.Validation/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225444750,"owners_count":17475353,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-19T23:45:49.957Z","updated_at":"2024-11-19T23:45:50.637Z","avatar_url":"https://github.com/Windows-XAML.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Validation in Universal Windows Platform\n\nIn Windows UWP XAML/C# apps, developers will discover that input controls do not support `DataAnnotation` or `ExceptionValidationRule` or `IDataErrorInfo` or `INotifyDataErrorInfo` or `BindingValidationError`. Even if the platform included these capabilities, there are significant limitations to each that make them a limiting option for application with significant real-world data validation requirements.\n\n![nuget](https://github.com/Windows-XAML/Template10.Validation/raw/master/Assets/Nuget.png)\n\n## Introducing Template10 Validation\n\nThese validation libraries provide UWP developers a comprehensive solution to data validation that solves problems in a realistic and usable way. The associated sample application demonstrates the use and syntax. If you have feedback or a bug to report, do it here: https://github.com/Windows-XAML/Template10/issues. \n\n## Get started\n\nTo get started with validation, your models need to inherit `Template10.Validation.ValidatableModelBase`. This will include an implementation of `INotifyPropertyChanged` in case you need it in your logic. Should your poco classes (models) not support inheriting from a new base class, then this validation library will not work for you. The enhancements to your model(s) will include:\n\n### ValidatableModelBase properties\n\n* `public ObservableCollection\u003cstring\u003e Errors { get; }`\n* `public bool IsDirty { get; }`\n* `public bool IsValid { get; }`\n* `public ObservableDictionary\u003cstring, IProperty\u003e Properties { get; }`\n* `public Action\u003cIValidatableModel\u003e Validator { get; set; }`\n\n### ValidatableModelBase methods\n\n* `public void MarkAsClean();`\n* `public void RaisePropertyChanged([CallerMemberName] string propertyName = null);`\n* `public void Revert();`\n* `public bool Validate();`\n* `protected T Read\u003cT\u003e([CallerMemberName] string propertyName = null);`\n* `protected void Write\u003cT\u003e(T value, [CallerMemberName] string propertyName = null, bool validateAfter = true);`\n\nIn addition to inheriting from `ValidatableModelBase`, both the setter and getters of your model properties will need to change to the following syntax in order to take part in the underlying change tracking mechanism.\n\n#### Your model before\n\n```csharp\npublic class User \n{\n    public int Id { get; set; }\n    public string FirstName { get; set; }\n    public string LastName { get; set; }\n    public override string ToString() =\u003e $\"{FirstName} {LastName}\";\n}\n```\n\n#### Your model after\n\n```csharp\npublic class User : Template10.Validation.ValidatableModelBase\n{\n    public int Id { get; set; }\n    public string FirstName { get { return Read\u003cstring\u003e(); } set { Write(value); } }\n    public string LastName { get { return Read\u003cstring\u003e(); } set { Write(value); } }\n    public override string ToString() =\u003e $\"{FirstName} {LastName}\";\n}\n```\n\n## Adding validation logic\n\nOnce you have implemented these changes, you need to set the `Validator` property of your model - typically when they are created or just before they are exposed in your view-model. (Note: It is not required that you use the MVVP design pattern to use this library - but if you don't you're probably building your app all wrong). You would set your validator something like this:\n\n```csharp\nvar user = new User\n{\n    FirstName = \"Jerry\",\n    LastName = \"Nixon\",\n    Validator = i =\u003e\n    {\n        var u = i as User;\n        if (string.IsNullOrEmpty(u.FirstName))\n        {\n            u.Properties[nameof(u.FirstName)].Errors.Add(\"First name is required\");\n        }\n        if (string.IsNullOrEmpty(u.LastName))\n        {\n            u.Properties[nameof(u.LastName)].Errors.Add(\"Last name is required\");\n        }\n    },\n};\n```\n\nNotice in the code above how you are adding one or more errors to the `Errors` property of the model's property; you are not adding to the `Errors` property of the model. This allows errors on a field level. Property errors are automatically propagated to the model-level property `Errors`. Any changes to that list will be overwritten.\n\n## Calling validation logic\n\nOnce the validation logic is injected into the model, you can call the model's `Validate()` method to assess the current state of the model. You can repeatedly call `Validate()` as the workflow in your app requires. If the validation logic has significant cost, calling `Validate()` too frequently could have a performance cost to your app. \n\n## New properties of your properties\n\nAbove you saw how each property has an `Errors` property. In addition, there is a `Value` property and these others:\n\n### Properties\n\n* `ObservableCollection \u003cstring\u003e Errors { get; }`\n* `bool IsDirty { get; }`\n* `bool IsOriginalSet { get; }`\n* `bool IsValid { get; }`\n* `T Value { get; set; }`\n* `T OriginalValue { get; set; }`\n\n### Event(s)\n\n* `event EventHandler ValueChanged;`\n\n### Methods\n\n* `void MarkAsClean();`\n* `void Revert();`\n\n## Error indicator\n\nYou will see that most of these properties are managed automatically by the base class. Calling `MarkAsClean()` or `Revert()` impacts `IsDirty` and `Value` respectively. That being said, you can also use them in tandem with the control wrapper that ships in the library. You would use it like this:\n\n```xaml\n\u003cvalidate:ControlWrapper PropertyName=\"FirstName\"\u003e\n    \u003cTextBox Width=\"{StaticResource FieldWidth}\"\n        Header=\"First Name\"\n        Text=\"{Binding FirstName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}\" /\u003e\n\u003c/validate:ControlWrapper\u003e\n```\n\nBy default the visual looks like this:\n\n![default look](https://github.com/Windows-XAML/Template10.Validation/raw/master/Assets/DefaultLook.png)\n\n## Customized error indicator\n\nThe visual definition of the wrapper is defined in the library (https://github.com/Windows-XAML/Template10.Validation/blob/master/Library/Themes/Generic.xaml) and you can override it simply by changing the `Template` property of the wrapper. Here's how you might do it:\n\n```xaml\n\u003cvalidate:ControlWrapper PropertyName=\"FirstName\"\u003e\n    \u003cvalidate:ControlWrapper.Template\u003e\n        \u003cControlTemplate TargetType=\"validate:ControlWrapper\"\u003e\n            \u003cStackPanel DataContext=\"{TemplateBinding Property}\"\u003e\n                \u003cTextBlock Text=\"IsValid\" /\u003e\n                \u003cTextBlock Text=\"{Binding IsValid}\" /\u003e\n                \u003cTextBlock Text=\"Errors\" /\u003e\n                \u003cTextBlock Text=\"{Binding Errors.Count}\" /\u003e\n                \u003cContentPresenter Content=\"{TemplateBinding Content}\" /\u003e\n            \u003c/StackPanel\u003e\n        \u003c/ControlTemplate\u003e\n    \u003c/validate:ControlWrapper.Template\u003e\n    \u003cTextBox Width=\"{StaticResource FieldWidth}\"\n                Header=\"First Name\"\n                Text=\"{Binding FirstName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}\" /\u003e\n\u003c/validate:ControlWrapper\u003e\n```\n\nIn the XAML above the `ControlTemplate` is created in-line, but could easily be moved to a resource and re-used in multiple controls. It also demonstrates how every control *could* have a separate look, if desired. The XAML above would render a look something like this: \n\n![custom look](https://github.com/Windows-XAML/Template10.Validation/raw/master/Assets/CustomLook.png)\n\nI realize that's a silly use of the control, but it demonstrates an easy starting place.\n\nI hope you enjoy Template 10 Validation!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwindows-xaml%2Ftemplate10.validation","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwindows-xaml%2Ftemplate10.validation","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwindows-xaml%2Ftemplate10.validation/lists"}