{"id":21129494,"url":"https://github.com/guorg/gu.wpf.validationscope","last_synced_at":"2025-09-10T16:40:11.122Z","repository":{"id":40372977,"uuid":"51255769","full_name":"GuOrg/Gu.Wpf.ValidationScope","owner":"GuOrg","description":"Form validation for WPF","archived":false,"fork":false,"pushed_at":"2023-12-25T16:11:46.000Z","size":961,"stargazers_count":38,"open_issues_count":5,"forks_count":9,"subscribers_count":11,"default_branch":"master","last_synced_at":"2024-11-07T19:08:36.431Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"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/GuOrg.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-02-07T16:56:44.000Z","updated_at":"2024-04-25T15:12:43.000Z","dependencies_parsed_at":"2023-11-06T13:45:45.828Z","dependency_job_id":"201951f2-5ab1-4e26-8738-270d3b802c1d","html_url":"https://github.com/GuOrg/Gu.Wpf.ValidationScope","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GuOrg%2FGu.Wpf.ValidationScope","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GuOrg%2FGu.Wpf.ValidationScope/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GuOrg%2FGu.Wpf.ValidationScope/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GuOrg%2FGu.Wpf.ValidationScope/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/GuOrg","download_url":"https://codeload.github.com/GuOrg/Gu.Wpf.ValidationScope/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225473208,"owners_count":17479744,"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-20T05:23:43.094Z","updated_at":"2024-11-20T05:23:43.764Z","avatar_url":"https://github.com/GuOrg.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Gu.Wpf.ValidationScope\n\n[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE.md)\n[![Gitter](https://badges.gitter.im/JohanLarsson/Gu.Wpf.ValidationScope.svg)](https://gitter.im/JohanLarsson/Gu.Wpf.ValidationScope?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n[![NuGet](https://img.shields.io/nuget/v/Gu.Wpf.ValidationScope.svg)](https://www.nuget.org/packages/Gu.Wpf.ValidationScope/)\n[![Build status](https://ci.appveyor.com/api/projects/status/omv9baijykp70dfr?svg=true)](https://ci.appveyor.com/project/JohanLarsson/gu-wpf-validationscope)\n[![Build Status](https://dev.azure.com/guorg/Gu.Wpf.ValidationScope/_apis/build/status/GuOrg.Gu.Wpf.ValidationScope?branchName=master)](https://dev.azure.com/guorg/Gu.Wpf.ValidationScope/_build/latest?definitionId=13\u0026branchName=master)\n\nLibrary that provides functionality for form validation in WPF.\nIt works by adding bindings to Validation.Errors for elements in a validation scope.\nAs bindings are somewhat expensive no bindings are added by default. The types to track errors for are specified using the `Scope.ForInputTypes`\n\nThe samples assumes an xml namespace alias `xmlns:validation=\"https://github.com/JohanLarsson/Gu.Wpf.ValidationScope\"` is defined.\n\n- [1. Sample:](#1-sample)\n- [2. Scope](#2-scope)\n  - [2.1. ForInputTypes](#21-forinputtypes)\n    - [2.1.1. Sample: Defining a scope for textboxes.](#211-sample--defining-a-scope-for-textboxes)\n    - [2.1.2. Sample: Defining a partial scope for textboxes.](#212-sample--defining-a-partial-scope-for-textboxes)\n    - [2.1.3 Valid values](#213-valid-values)\n      - [2.1.3.1 Typenames](#2131-typenames)\n      - [2.1.3.2 Fully qualified Typenames](#2132-fully-qualified-typenames)\n      - [2.1.3.3 IEnumebarble\u003cT\u003e](#2133-ienumebarble-t)\n      - [2.1.3.4 InputTypeCollection.Default](#2134-inputtypecollectiondefault)\n      - [2.1.3.5 InputTypes markupextension](#2135-inputtypes-markupextension)\n  - [2.2. HasError](#22-haserror)\n  - [2.3. Errors](#23-errors)\n  - [2.4. Node](#24-node)\n  - [2.5. ErrorEvent](#25-errorevent)\n  - [2.6. ErrorsChangedEvent](#26-errorschangedevent)\n  - [2.7. OneWayToSourceBindings](#27-onewaytosourcebindings)\n- [3. InputTypeCollection](#3-inputtypecollection)\n  - [3.1. Default](#31-default)\n- [4. InputTypes markupextension](#4-inputtypes-markupextension)\n- [5. Node](#5-node)\n  - [5.1. HasError](#51-haserror)\n  - [5.2. Errors](#52-errors)\n  - [5.3. Children](#53-children)\n  - [5.4 Node types](#54-node-types)\n    - [5.4.1 InputNode](#541-inputnode)\n    - [5.4.2 ScopeNode](#542-scopenode)\n    - [5.4.3 ValidNode](#543-validnode)\n\n# 1. Sample:\n*BoolToBrushConverter is not included in the nuget. Check the demo project if interested.\n\n```xaml\n\u003cGrid\u003e\n    \u003cGrid.RowDefinitions\u003e\n        \u003cRowDefinition Height=\"Auto\" /\u003e\n        \u003cRowDefinition Height=\"Auto\" /\u003e\n        \u003cRowDefinition Height=\"*\" /\u003e\n    \u003c/Grid.RowDefinitions\u003e\n    \u003cBorder BorderBrush=\"{Binding Path=(validation:Scope.HasError),\n                                  Converter={local:BoolToBrushConverter WhenTrue=Red, WhenFalse=Black},\n                                  ElementName=Form}\"\n            BorderThickness=\"1\"\u003e\n        \u003cGrid x:Name=\"Form\"\n                validation:Scope.ForInputTypes=\"TextBox\"\u003e\n                \u003c!-- this is where we define our scope, we do so by telling the scope what types of control sto track --\u003e\n            \u003cGrid.RowDefinitions\u003e\n                \u003cRowDefinition Height=\"Auto\" /\u003e\n                \u003cRowDefinition Height=\"Auto\" /\u003e\n                \u003cRowDefinition /\u003e\n            \u003c/Grid.RowDefinitions\u003e\n            \u003cGrid.ColumnDefinitions\u003e\n                \u003cColumnDefinition Width=\"Auto\" /\u003e\n                \u003cColumnDefinition /\u003e\n            \u003c/Grid.ColumnDefinitions\u003e\n            \u003cTextBlock Grid.Row=\"0\"\n                       Grid.Column=\"0\"\n                       Text=\"IntValue1\" /\u003e\n            \u003cTextBox Grid.Row=\"0\"\n                     Grid.Column=\"1\"\n                     Text=\"{Binding IntValue1,\n                                    UpdateSourceTrigger=PropertyChanged}\" /\u003e\n            \u003cTextBlock Grid.Row=\"1\"\n                       Grid.Column=\"0\"\n                       Text=\"IntValue2\" /\u003e\n            \u003cTextBox Grid.Row=\"1\"\n                     Grid.Column=\"1\"\n                     Text=\"{Binding IntValue2,\n                     UpdateSourceTrigger=PropertyChanged}\" /\u003e\n        \u003c/Grid\u003e\n    \u003c/Border\u003e\n\n    \u003cItemsControl Grid.Row=\"1\"\n                  ItemsSource=\"{Binding Path=(validation:Scope.Errors),\n                                        ElementName=Form}\"\u003e\n        \u003cItemsControl.ItemTemplate\u003e\n            \u003cDataTemplate DataType=\"{x:Type ValidationError}\"\u003e\n                \u003cTextBlock Foreground=\"Red\"\n                           Text=\"{Binding ErrorContent}\" /\u003e\n            \u003c/DataTemplate\u003e\n        \u003c/ItemsControl.ItemTemplate\u003e\n    \u003c/ItemsControl\u003e\n\u003c/Grid\u003e\n```\n\nRenders:\n\n![ItemsSource2D render](http://i.imgur.com/EkuWA9c.gif)\n\nMore samples in the demo project\n\n# 2. Scope\n## 2.1. ForInputTypes\nBy setting `ForInputTypes` we specify what type of elements to track in the validation scope. Most of the times only TextBoxes will be relevant.\nThe `ForInputTypes` inherits so setting it on one element sets it to all chidlren unless explicitly set to something else for a child.\nSetting `validation:Scope.ForInputTypes=\"{x:Null}\"` means that errors are not tracked for nodes below this element.\nSetting `validation:Scope.ForInputTypes=\"Scope\"` means that only errors from subscopes are tracked.\nThe default value is null meaning no scope is defined.\n\n### 2.1.1. Sample: Defining a scope for textboxes.\n```xaml\n\u003cBorder validation:Scope.ForInputTypes=\"TextBox\"\u003e\n    \u003cStackPanel\u003e\n        \u003c!--The stackpanel will inherit the scope--\u003e\n        \u003cTextBox Text=\"{Binding Value1}\" /\u003e\n        \u003cTextBox Text=\"{Binding Value2}\" /\u003e\n        \u003cComboBox ItemsSource=\"{Binding Values}\" Text=\"{Binding Value3}\" /\u003e\n        \u003c!-- this combobox will not be tracked because the scope is only for textboxes and sliders--\u003e \n    \u003c/StackPanel\u003e\n\u003c/Border\u003e\n```\n\n### 2.1.2. Sample: Defining a partial scope for textboxes.\n```xaml\n\u003cBorder validation:Scope.ForInputTypes=\"Scope\"\u003e\n    \u003cStackPanel validation:Scope.ForInputTypes=\"TextBox\"\u003e\n        \u003cTextBox Text=\"{Binding Value1}\" /\u003e\n        \u003cTextBox Text=\"{Binding Value2}\" /\u003e\n    \u003c/StackPanel\u003e\n\t\u003cStackPanel validation:Scope.ForInputTypes=\"{x:null}\"\u003e\n\t\t\u003c!-- No tracking of errors for these textboxes, due to ForInputTypes=\"{x:null}\". --\u003e\n        \u003cTextBox Text=\"{Binding Value1}\" /\u003e\n        \u003cTextBox Text=\"{Binding Value2}\" /\u003e\n    \u003c/StackPanel\u003e\n\u003c/Border\u003e\n```\n\n### 2.1.3 Valid values\nTypes must be elements deriving from `UIElement`\n#### 2.1.3.1 Typenames\n`\u003cBorder validation:Scope.ForInputTypes=\"TextBox, ComboBox\" ...\u003e`\n\n#### 2.1.3.2 Fully qualified Typenames\n`\u003cBorder validation:Scope.ForInputTypes=\"System.Windows.Controls.TextBox, ComboBox\" ...\u003e`\n\n#### 2.1.3.3 IEnumebarble\u003cT\u003e\n`\u003cBorder validation:Scope.ForInputTypes=\"{Binding ScopeTypes}\" ...\u003e`\n\n#### 2.1.3.4 InputTypeCollection.Default\n`\u003cBorder validation:Scope.ForInputTypes=\"{x:Static validation:InputTypeCollection.Default}\" ...\u003e`\n\n#### 2.1.3.5 InputTypes markupextension\n`\u003cBorder validation:Scope.ForInputTypes=\"{validation:InputTypes {x:Type TextBox}, {x:Type ComboBox}}\" ...\u003e`\n\n## 2.2. HasError\nA bool indicating if there is a validation error in the scope. Similar to `System.Controls.Validation.HasError`\n\n```xaml\n\u003cBorder BorderBrush=\"{Binding Path=(validation:Scope.HasError), \n                              Converter={local:BoolToBrushConverter WhenTrue=Red, WhenFalse=Transparent}, \n\t\t\t\t\t\t\t  ElementName=Form}\" \n        BorderThickness=\"1\"\u003e\n    \u003cStackPanel x:Name=\"Form\" validation:Scope.ForInputTypes=\"TextBox\"\u003e\n        \u003cTextBox Text=\"{Binding Value1}\" /\u003e\n        \u003cTextBox Text=\"{Binding Value2}\" /\u003e\n    \u003c/StackPanel\u003e\n\u003c/Border\u003e\n```\n\n## 2.3. Errors\nA `ReadOnlyObservableCollection\u003cValidationError\u003e` with the errors in the scope. Similar to `System.Controls.Validation.Errors`\n\n```xaml\n\u003cStackPanel\u003e\n    \u003cStackPanel x:Name=\"Form\" validation:Scope.ForInputTypes=\"TextBox\"\u003e\n        \u003cTextBox Text=\"{Binding Value1}\" /\u003e\n        \u003cTextBox Text=\"{Binding Value2}\" /\u003e\n    \u003c/StackPanel\u003e\n\t\u003cTextBlock Foreground=\"Red\" Text=\"{Binding (validation:Scope.Errors).Count, ElementName=Form, StringFormat='Errors: {0}'}\" /\u003e\n\u003c/StackPanel\u003e\n```\n\n## 2.4. Node\nA `Node` in the tree that is the validation scope.\n\n```xaml\n\u003cStackPanel\u003e\n    \u003cStackPanel x:Name=\"Form\" validation:Scope.ForInputTypes=\"TextBox\"\u003e\n        \u003cTextBox Text=\"{Binding Value1}\" /\u003e\n        \u003cTextBox Text=\"{Binding Value2}\" /\u003e\n    \u003c/StackPanel\u003e\n\t\u003cTextBlock Foreground=\"Red\" Text=\"{Binding (validation:Scope.Node).Children.Count, ElementName=Form, StringFormat='Children: {0}'}\" /\u003e\n\u003c/StackPanel\u003e\n```\n\n## 2.5. ErrorEvent\nAn event that notifies when errors are added and removed. Similar to `System.Windows.Controls.Validation.ErrorEvent`\nDoes not require bindings to have `NotifyOnValidationError=True`\n\n```xaml\n\u003cStackPanel\u003e\n    \u003cStackPanel validation:Scope.ForInputTypes=\"TextBox\"\n\t\t\t\tvalidation:Scope.Error=\"OnValidationError\"\u003e\n        \u003cTextBox Text=\"{Binding Value1}\" /\u003e\n        \u003cTextBox Text=\"{Binding Value2}\" /\u003e\n    \u003c/StackPanel\u003e\n\u003c/StackPanel\u003e\n```\n\n## 2.6. ErrorsChangedEvent\nAn event that notifies when errors are added and removed. The `ErrorEvent` notifies about each add and remove while `ErrorsChangedEvent`notifies once with a all added and removed events.\nDoes not require bindings to have `NotifyOnValidationError=True`\n\n```xaml\n\u003cStackPanel\u003e\n    \u003cStackPanel validation:Scope.ForInputTypes=\"TextBox\"\n\t\t\t\tvalidation:Scope.Error=\"OnValidationError\"\u003e\n        \u003cTextBox Text=\"{Binding Value1}\" /\u003e\n        \u003cTextBox Text=\"{Binding Value2}\" /\u003e\n    \u003c/StackPanel\u003e\n\u003c/StackPanel\u003e\n```\n\n## 2.7. OneWayToSourceBindings\nWPF does not allow binding readonly dependency properties even with `Mode=OneWayToSource`.\nAs a workaround for this OneWayToSourceBindings can be used like this:\n\n```xaml\n\u003cStackPanel x:Name=\"Form\" validation:Scope.ForInputTypes=\"TextBox\"\u003e\n    \u003cvalidation:Scope.OneWayToSourceBindings\u003e\n        \u003cvalidation:OneWayToSourceBindings Errors=\"{Binding Errors}\"\n                                           HasError=\"{Binding HasError}\"\n                                           Node=\"{Binding Node}\" /\u003e\n    \u003c/validation:Scope.OneWayToSourceBindings\u003e\n    \u003cTextBox Text=\"{Binding Value1}\" /\u003e\n    \u003cTextBox Text=\"{Binding Value2}\" /\u003e\n\u003c/StackPanel\u003e\n```\n\n# 3. InputTypeCollection\n## 3.1. Default\nContains the following types `{ typeof(Scope), typeof(TextBoxBase), typeof(Selector), typeof(ToggleButton), typeof(Slider) }`\nAnd should be enough for most scenarios when you don't have third party controls for example a third party textbox that does not derive from `TextBoxBase`\n\n# 4. InputTypes markupextension\nExposed for convenience to create list of types in xaml.\n\n`\u003cBorder validation:Scope.ForInputTypes=\"{validation:InputTypes {x:Type TextBox}, {x:Type ComboBox}}\"\u003e`\n\n# 5. Node\nThe validation scope is a tree of nodes.\n## 5.1. HasError\nA bool indicating if there is a validation error in the scope. Similar to `System.Controls.Validation.HasError`\n\n## 5.2. Errors\nA `ReadOnlyObservableCollection\u003cValidationError\u003e` with the errors in the scope. Similar to `System.Controls.Validation.Errors`\n\n## 5.3. Children\nA `ReadOnlyObservableCollection\u003cErrorNode\u003e` with the child nodes which have errors in the scope.\n\n## 5.4 Node types\n\n### 5.4.1 InputNode\nThis node type is used for elements for which we track errors.\n\n### 5.4.2 ScopeNode\nThis node type is used for elements which has subnodes with errors.\nThis node type does not listen to validation errors for its source element.\n\n### 5.4.3 ValidNode\nThis node type is used for elements which has no errors or are not in a scope.\nThis is immutable and a single instance is used for all.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fguorg%2Fgu.wpf.validationscope","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fguorg%2Fgu.wpf.validationscope","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fguorg%2Fgu.wpf.validationscope/lists"}