├── .editorconfig
├── .gitignore
├── CommonAssemblyInfo.cs
├── Examples
├── FormValidationExample
│ ├── App.xaml
│ ├── App.xaml.cs
│ ├── FormValidationExample.csproj
│ ├── Infrastructure
│ │ ├── PasswordBoxAssistant.cs
│ │ └── ValidatableViewModelBase.cs
│ ├── MainWindow.xaml
│ ├── MainWindow.xaml.cs
│ ├── Properties
│ │ ├── AssemblyInfo.cs
│ │ ├── Resources.Designer.cs
│ │ ├── Resources.resx
│ │ ├── Settings.Designer.cs
│ │ └── Settings.settings
│ ├── Services
│ │ ├── IUserRegistrationService.cs
│ │ └── UserRegistrationService.cs
│ ├── View
│ │ ├── FormControl.xaml
│ │ ├── FormControl.xaml.cs
│ │ ├── InterestSelectorView.xaml
│ │ ├── InterestSelectorView.xaml.cs
│ │ ├── MainView.xaml
│ │ └── MainView.xaml.cs
│ ├── ViewModel
│ │ ├── InterestItemViewModel.cs
│ │ ├── InterestSelectorViewModel.cs
│ │ ├── MainViewModel.cs
│ │ └── NameInfo.cs
│ ├── app.config
│ └── packages.config
├── Lib
│ └── .NETFramework
│ │ ├── Microsoft.Expression.Interactions.dll
│ │ ├── Microsoft.Expression.Interactions.xml
│ │ ├── System.Windows.Interactivity.dll
│ │ └── System.Windows.Interactivity.xml
└── screenshot.png
├── Key.snk
├── LICENSE.md
├── MvvmValidation.Portable
├── IAsyncValidationRule.cs
├── IValidatable.cs
├── IValidationResultFormatter.cs
├── IValidationRule.cs
├── Internal
│ ├── AutoToggle.cs
│ ├── CallerInfoAttributes.cs
│ ├── CollectionUtils.cs
│ ├── DelegateDisposable.cs
│ ├── ExceptionUtils.cs
│ ├── GenericValidationTarget.cs
│ ├── Guard.cs
│ ├── GuardReSharperTemplates.cs
│ ├── IValidationTarget.cs
│ ├── PropertyCollectionValidationTarget.cs
│ ├── PropertyName.cs
│ ├── PropertyValidationTarget.cs
│ ├── TaskEx.cs
│ ├── UndefinedValidationTarget.cs
│ ├── ValidationRule.cs
│ └── ValidationRuleCollection.cs
├── MvvmValidation.Portable.csproj
├── NotifyDataErrorInfoAdapter.cs
├── NumberedListValidationResultFormatter.cs
├── Properties
│ └── AssemblyInfo.cs
├── RuleResult.cs
├── RuleResultExtensions.cs
├── ValidationError.cs
├── ValidationErrorCollection.cs
├── ValidationException.cs
├── ValidationHelper.cs
├── ValidationHelperExtensions.cs
├── ValidationResult.cs
├── ValidationResultChangedEventArgs.cs
├── ValidationResultExtensions.cs
├── ValidationRuleSettings.cs
├── ValidationScope.cs
└── ValidationSettings.cs
├── MvvmValidation.Tests
├── Fakes
│ ├── DummyViewModel.cs
│ ├── FakeException.cs
│ ├── MockViewModel.cs
│ ├── ValidatableViewModel.cs
│ └── ViewModelBase.cs
├── Helpers
│ └── TestUtil.cs
├── IntegrationTests
│ └── ValidationHelperIntegrationTests.cs
├── MvvmValidation.Tests.crunchproject.local.xml
├── MvvmValidation.Tests.csproj
├── NumberedListValidationResultFormatterTests.cs
├── Properties
│ └── AssemblyInfo.cs
├── ValidationHelperTests.cs
└── packages.config
├── MvvmValidation.sln
├── MvvmValidation.sln.DotSettings
├── Package.nuspec
├── README.md
├── Tools
├── Build
│ ├── MSBuild.Community.Tasks.Targets
│ ├── MSBuild.Community.Tasks.dll
│ ├── MSBuild.Community.Tasks.pdb
│ ├── MSBuild.Community.Tasks.xml
│ └── MSBuild.Community.Tasks.xsd
└── NuGet.exe
├── VersionInfo.cs
├── build.cmd
├── build.msbuild
└── nuget-publish.ps1
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Rules in this file were initially inferred by Visual Studio IntelliCode from the D:\Pasha\Dev\MyProjects\MvvmValidation codebase based on best match to current usage at 3/11/2021
2 | # You can modify the rules from these initially generated values to suit your own policies
3 | # You can learn more about editorconfig here: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference
4 | [*.cs]
5 |
6 |
7 | #Core editorconfig formatting - indentation
8 |
9 | #use soft tabs (spaces) for indentation
10 | indent_size = 4
11 | indent_style = space
12 | tab_width = 4
13 |
14 | #Formatting - new line options
15 |
16 | #place else statements on a new line
17 | csharp_new_line_before_else = true
18 | #require members of object intializers to be on separate lines
19 | csharp_new_line_before_members_in_object_initializers = true
20 | #require braces to be on a new line for accessors, methods, control_blocks, types, lambdas, and properties (also known as "Allman" style)
21 | csharp_new_line_before_open_brace = accessors, methods, control_blocks, types, lambdas, properties
22 |
23 | #Formatting - organize using options
24 |
25 | #sort System.* using directives alphabetically, and place them before other usings
26 | dotnet_sort_system_directives_first = true
27 |
28 | #Formatting - spacing options
29 |
30 | #require a space between a cast and the value
31 | csharp_space_after_cast = true
32 | #require a space before the colon for bases or interfaces in a type declaration
33 | csharp_space_after_colon_in_inheritance_clause = true
34 | #require a space after a keyword in a control flow statement such as a for loop
35 | csharp_space_after_keywords_in_control_flow_statements = true
36 | #require a space before the colon for bases or interfaces in a type declaration
37 | csharp_space_before_colon_in_inheritance_clause = true
38 | #remove space within empty argument list parentheses
39 | csharp_space_between_method_call_empty_parameter_list_parentheses = false
40 | #remove space between method call name and opening parenthesis
41 | csharp_space_between_method_call_name_and_opening_parenthesis = false
42 | #do not place space characters after the opening parenthesis and before the closing parenthesis of a method call
43 | csharp_space_between_method_call_parameter_list_parentheses = false
44 | #remove space within empty parameter list parentheses for a method declaration
45 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
46 | #place a space character after the opening parenthesis and before the closing parenthesis of a method declaration parameter list.
47 | csharp_space_between_method_declaration_parameter_list_parentheses = false
48 |
49 | #Formatting - wrapping options
50 |
51 | #leave code block on single line
52 | csharp_preserve_single_line_blocks = true
53 |
54 | #Style - Code block preferences
55 |
56 | #prefer curly braces even for one line of code
57 | csharp_prefer_braces = true:suggestion
58 |
59 | #Style - expression bodied member options
60 |
61 | #prefer block bodies for accessors
62 | csharp_style_expression_bodied_accessors = false:suggestion
63 | #prefer block bodies for constructors
64 | csharp_style_expression_bodied_constructors = false:suggestion
65 | #prefer block bodies for methods
66 | csharp_style_expression_bodied_methods = false:suggestion
67 | #prefer block bodies for properties
68 | csharp_style_expression_bodied_properties = false:suggestion
69 |
70 | #Style - expression level options
71 |
72 | #prefer the language keyword for member access expressions, instead of the type name, for types that have a keyword to represent them
73 | dotnet_style_predefined_type_for_member_access = true:suggestion
74 |
75 | #Style - implicit and explicit types
76 |
77 | #prefer var over explicit type in all cases, unless overridden by another code style rule
78 | csharp_style_var_elsewhere = true:suggestion
79 | #prefer explicit type over var to declare variables with built-in system types such as int
80 | csharp_style_var_for_built_in_types = false:suggestion
81 | #prefer var when the type is already mentioned on the right-hand side of a declaration expression
82 | csharp_style_var_when_type_is_apparent = true:suggestion
83 |
84 | #Style - language keyword and framework type options
85 |
86 | #prefer the language keyword for local variables, method parameters, and class members, instead of the type name, for types that have a keyword to represent them
87 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
88 |
89 | #Style - Miscellaneous preferences
90 |
91 | #prefer anonymous functions over local functions
92 | csharp_style_pattern_local_over_anonymous_function = false:suggestion
93 |
94 | #Style - modifier options
95 |
96 | #prefer accessibility modifiers to be declared except for public interface members. This will currently not differ from always and will act as future proofing for if C# adds default interface methods.
97 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
98 |
99 | #Style - Modifier preferences
100 |
101 | #when this rule is set to a list of modifiers, prefer the specified ordering.
102 | csharp_preferred_modifier_order = public,private,internal,protected,static,override,readonly,async,sealed,virtual:suggestion
103 |
104 | #Style - Pattern matching
105 |
106 | #prefer is expression with type casts instead of pattern matching
107 | csharp_style_pattern_matching_over_as_with_null_check = false:suggestion
108 |
109 | #Style - qualification options
110 |
111 | #prefer events not to be prefaced with this. or Me. in Visual Basic
112 | dotnet_style_qualification_for_event = false:suggestion
113 | #prefer fields not to be prefaced with this. or Me. in Visual Basic
114 | dotnet_style_qualification_for_field = false:suggestion
115 | #prefer methods not to be prefaced with this. or Me. in Visual Basic
116 | dotnet_style_qualification_for_method = false:suggestion
117 | #prefer properties not to be prefaced with this. or Me. in Visual Basic
118 | dotnet_style_qualification_for_property = false:suggestion
119 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #################
2 | ## Eclipse
3 | #################
4 |
5 | *.pydevproject
6 | .project
7 | .metadata
8 | bin/
9 | tmp/
10 | *.tmp
11 | *.bak
12 | *.swp
13 | *~.nib
14 | local.properties
15 | .classpath
16 | .settings/
17 | .loadpath
18 |
19 | # External tool builders
20 | .externalToolBuilders/
21 |
22 | # Locally stored "Eclipse launch configurations"
23 | *.launch
24 |
25 | # CDT-specific
26 | .cproject
27 |
28 | # PDT-specific
29 | .buildpath
30 |
31 |
32 | #################
33 | ## Visual Studio
34 | #################
35 |
36 | ## Ignore Visual Studio temporary files, build results, and
37 | ## files generated by popular Visual Studio add-ons.
38 |
39 | # User-specific files
40 | *.suo
41 | *.user
42 | *.sln.docstates
43 |
44 | # Build results
45 |
46 | x64/
47 | [Bb]in/
48 | [Oo]bj/
49 |
50 | # MSTest test Results
51 | [Tt]est[Rr]esult*/
52 | [Bb]uild[Ll]og.*
53 |
54 | *_i.c
55 | *_p.c
56 | *.ilk
57 | *.meta
58 | *.obj
59 | *.pch
60 | *.pdb
61 | *.pgc
62 | *.pgd
63 | *.rsp
64 | *.sbr
65 | *.tlb
66 | *.tli
67 | *.tlh
68 | *.tmp
69 | *.tmp_proj
70 | *.log
71 | *.vspscc
72 | *.vssscc
73 | .builds
74 | *.pidb
75 | *.log
76 | *.scc
77 |
78 | # Visual C++ cache files
79 | ipch/
80 | *.aps
81 | *.ncb
82 | *.opensdf
83 | *.sdf
84 | *.cachefile
85 |
86 | # Visual Studio profiler
87 | *.psess
88 | *.vsp
89 | *.vspx
90 |
91 | # Guidance Automation Toolkit
92 | *.gpState
93 |
94 | # ReSharper is a .NET coding add-in
95 | _ReSharper*/
96 | *.[Rr]e[Ss]harper
97 |
98 | # TeamCity is a build add-in
99 | _TeamCity*
100 |
101 | # DotCover is a Code Coverage Tool
102 | *.dotCover
103 |
104 | # NCrunch
105 | *.ncrunch*
106 | .*crunch*.local.xml
107 |
108 | # Installshield output folder
109 | [Ee]xpress/
110 |
111 | # DocProject is a documentation generator add-in
112 | DocProject/buildhelp/
113 | DocProject/Help/*.HxT
114 | DocProject/Help/*.HxC
115 | DocProject/Help/*.hhc
116 | DocProject/Help/*.hhk
117 | DocProject/Help/*.hhp
118 | DocProject/Help/Html2
119 | DocProject/Help/html
120 |
121 | # Click-Once directory
122 | publish/
123 |
124 | # Publish Web Output
125 | *.Publish.xml
126 | *.pubxml
127 |
128 | # NuGet Packages Directory
129 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line
130 | #packages/
131 |
132 | # Windows Azure Build Output
133 | csx
134 | *.build.csdef
135 |
136 | # Windows Store app package directory
137 | AppPackages/
138 |
139 | # Others
140 | sql/
141 | *.Cache
142 | ClientBin/
143 | [Ss]tyle[Cc]op.*
144 | ~$*
145 | *~
146 | *.dbmdl
147 | *.[Pp]ublish.xml
148 | *.pfx
149 | *.publishsettings
150 |
151 | # RIA/Silverlight projects
152 | Generated_Code/
153 |
154 | # Backup & report files from converting an old project file to a newer
155 | # Visual Studio version. Backup files are not needed, because we have git ;-)
156 | _UpgradeReport_Files/
157 | Backup*/
158 | UpgradeLog*.XML
159 | UpgradeLog*.htm
160 |
161 | # SQL Server files
162 | App_Data/*.mdf
163 | App_Data/*.ldf
164 |
165 | #############
166 | ## Windows detritus
167 | #############
168 |
169 | # Windows image file caches
170 | Thumbs.db
171 | ehthumbs.db
172 |
173 | # Folder config file
174 | Desktop.ini
175 |
176 | # Recycle Bin used on file shares
177 | $RECYCLE.BIN/
178 |
179 | # Mac crap
180 | .DS_Store
181 |
182 |
183 | #############
184 | ## Python
185 | #############
186 |
187 | *.py[co]
188 |
189 | # Packages
190 | *.egg
191 | *.egg-info
192 | dist/
193 | eggs/
194 | var/
195 | sdist/
196 | develop-eggs/
197 | .installed.cfg
198 |
199 | # Installer logs
200 | pip-log.txt
201 |
202 | # Unit test / coverage reports
203 | .coverage
204 | .tox
205 |
206 | #Translations
207 | *.mo
208 |
209 | #Mr Developer
210 | .mr.developer.cfg
211 | /Temp
212 | /.vs/config/applicationhost.config
213 | /Linqua.WindowsPhone/BundleArtifacts/arm.txt
214 | /Output
215 | /TestReport.html
216 | /packages
217 | /.idea
218 | /.vs
219 |
--------------------------------------------------------------------------------
/CommonAssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 |
3 | // General Information about an assembly is controlled through the following
4 | // set of attributes. Change these attribute values to modify the information
5 | // associated with an assembly.
6 |
7 | [assembly: AssemblyTitle("MvvmValidation")]
8 | [assembly: AssemblyDescription("")]
9 | [assembly: AssemblyConfiguration("")]
10 | [assembly: AssemblyCompany("Pavlo Glazkov")]
11 | [assembly: AssemblyProduct("MVVM Validation Helpers")]
12 | [assembly: AssemblyCopyright("© 2016 Pavlo Glazkov")]
13 | [assembly: AssemblyTrademark("")]
14 | [assembly: AssemblyCulture("")]
--------------------------------------------------------------------------------
/Examples/FormValidationExample/App.xaml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
19 |
20 |
25 |
31 |
34 |
37 |
38 |
39 |
40 |
49 |
54 |
55 |
56 |
57 |
87 |
88 |
89 |
90 |
94 |
98 |
99 |
--------------------------------------------------------------------------------
/Examples/FormValidationExample/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Threading;
3 | using MvvmValidation;
4 |
5 | namespace FormValidationExample
6 | {
7 | ///
8 | /// Interaction logic for App.xaml
9 | ///
10 | public partial class App : Application
11 | {
12 | #region Overrides of Application
13 |
14 | protected override void OnStartup(StartupEventArgs e)
15 | {
16 | base.OnStartup(e);
17 |
18 | this.DispatcherUnhandledException += OnUnhandledException;
19 | }
20 |
21 | private void OnUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
22 | {
23 | if (e.Exception is ValidationException)
24 | {
25 | MessageBox.Show(MainWindow, e.Exception.ToString());
26 | }
27 | }
28 |
29 | #endregion
30 | }
31 | }
--------------------------------------------------------------------------------
/Examples/FormValidationExample/FormValidationExample.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | x86
6 | 8.0.30703
7 | 2.0
8 | {0FAB2AD2-EE78-49DF-8043-A5DF3BADEBDD}
9 | WinExe
10 | Properties
11 | FormValidationExample
12 | FormValidationExample
13 | v4.5.1
14 |
15 |
16 | 512
17 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
18 | 4
19 | 4.0.20525.0
20 |
21 |
22 |
23 |
24 | x86
25 | true
26 | full
27 | false
28 | bin\Debug\
29 | DEBUG;TRACE
30 | prompt
31 | 4
32 | false
33 |
34 |
35 | x86
36 | pdbonly
37 | true
38 | bin\Release\
39 | TRACE
40 | prompt
41 | 4
42 | false
43 |
44 |
45 |
46 | ..\..\packages\MvvmLightLibs.5.3.0.0\lib\net45\GalaSoft.MvvmLight.dll
47 | True
48 |
49 |
50 | ..\..\packages\MvvmLightLibs.5.3.0.0\lib\net45\GalaSoft.MvvmLight.Extras.dll
51 | True
52 |
53 |
54 | ..\..\packages\MvvmLightLibs.5.3.0.0\lib\net45\GalaSoft.MvvmLight.Platform.dll
55 | True
56 |
57 |
58 | ..\..\packages\Unofficial.Blend.Interactivity.1.0.0\lib\net45\Microsoft.Expression.Interactions.dll
59 |
60 |
61 | ..\..\packages\CommonServiceLocator.1.3\lib\portable-net4+sl5+netcore45+wpa81+wp8\Microsoft.Practices.ServiceLocation.dll
62 | True
63 |
64 |
65 |
66 |
67 | ..\..\packages\Rx-Core.2.2.2\lib\net45\System.Reactive.Core.dll
68 |
69 |
70 | ..\..\packages\Rx-Interfaces.2.2.2\lib\net45\System.Reactive.Interfaces.dll
71 |
72 |
73 | ..\..\packages\Rx-Linq.2.2.2\lib\net45\System.Reactive.Linq.dll
74 |
75 |
76 | ..\..\packages\Rx-PlatformServices.2.2.2\lib\net45\System.Reactive.PlatformServices.dll
77 |
78 |
79 | ..\..\packages\MvvmLightLibs.5.3.0.0\lib\net45\System.Windows.Interactivity.dll
80 | True
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 | 4.0
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 | MSBuild:Compile
97 | Designer
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 | FormControl.xaml
109 |
110 |
111 | InterestSelectorView.xaml
112 |
113 |
114 | MainView.xaml
115 |
116 |
117 | MSBuild:Compile
118 | Designer
119 |
120 |
121 | MSBuild:Compile
122 | Designer
123 |
124 |
125 | App.xaml
126 | Code
127 |
128 |
129 | MainWindow.xaml
130 | Code
131 |
132 |
133 | MSBuild:Compile
134 | Designer
135 |
136 |
137 | MSBuild:Compile
138 | Designer
139 |
140 |
141 |
142 |
143 | Code
144 |
145 |
146 | True
147 | True
148 | Resources.resx
149 |
150 |
151 | True
152 | Settings.settings
153 | True
154 |
155 |
156 | ResXFileCodeGenerator
157 | Resources.Designer.cs
158 |
159 |
160 | Designer
161 |
162 |
163 |
164 | SettingsSingleFileGenerator
165 | Settings.Designer.cs
166 |
167 |
168 |
169 |
170 |
171 | {6c8f3cb8-ea5f-4e72-b804-a10081df47e5}
172 | MvvmValidation.Portable
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
188 |
--------------------------------------------------------------------------------
/Examples/FormValidationExample/Infrastructure/PasswordBoxAssistant.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Controls;
3 |
4 | namespace FormValidationExample.Infrastructure
5 | {
6 | public static class PasswordBoxAssistant
7 | {
8 | public static readonly DependencyProperty BoundPassword =
9 | DependencyProperty.RegisterAttached("BoundPassword", typeof(string), typeof(PasswordBoxAssistant),
10 | new PropertyMetadata(string.Empty, OnBoundPasswordChanged));
11 |
12 | public static readonly DependencyProperty BindPassword = DependencyProperty.RegisterAttached(
13 | "BindPassword", typeof(bool), typeof(PasswordBoxAssistant),
14 | new PropertyMetadata(false, OnBindPasswordChanged));
15 |
16 | private static readonly DependencyProperty UpdatingPassword =
17 | DependencyProperty.RegisterAttached("UpdatingPassword", typeof(bool), typeof(PasswordBoxAssistant),
18 | new PropertyMetadata(false));
19 |
20 | private static void OnBoundPasswordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
21 | {
22 | var box = (PasswordBox) d;
23 |
24 | // only handle this event when the property is attached to a PasswordBox
25 | // and when the BindPassword attached property has been set to true
26 | if (d == null || !GetBindPassword(d))
27 | {
28 | return;
29 | }
30 |
31 | // avoid recursive updating by ignoring the box's changed event
32 | box.PasswordChanged -= HandlePasswordChanged;
33 |
34 | var newPassword = (string) e.NewValue;
35 |
36 | if (!GetUpdatingPassword(box))
37 | {
38 | box.Password = newPassword ?? string.Empty;
39 | }
40 |
41 | box.LostFocus += HandlePasswordChanged;
42 | }
43 |
44 | private static void OnBindPasswordChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
45 | {
46 | // when the BindPassword attached property is set on a PasswordBox,
47 | // start listening to its PasswordChanged event
48 |
49 | var box = (PasswordBox) dp;
50 |
51 | if (box == null)
52 | {
53 | return;
54 | }
55 |
56 | var wasBound = (bool) (e.OldValue);
57 | var needToBind = (bool) (e.NewValue);
58 |
59 | if (wasBound)
60 | {
61 | box.LostFocus -= HandlePasswordChanged;
62 | }
63 |
64 | if (needToBind)
65 | {
66 | box.LostFocus += HandlePasswordChanged;
67 | }
68 | }
69 |
70 | private static void HandlePasswordChanged(object sender, RoutedEventArgs e)
71 | {
72 | var box = (PasswordBox) sender;
73 |
74 | // set a flag to indicate that we're updating the password
75 | SetUpdatingPassword(box, true);
76 | // push the new password into the BoundPassword property
77 | SetBoundPassword(box, box.Password);
78 | SetUpdatingPassword(box, false);
79 | }
80 |
81 | public static void SetBindPassword(DependencyObject dp, bool value)
82 | {
83 | dp.SetValue(BindPassword, value);
84 | }
85 |
86 | public static bool GetBindPassword(DependencyObject dp)
87 | {
88 | return (bool) dp.GetValue(BindPassword);
89 | }
90 |
91 | public static string GetBoundPassword(DependencyObject dp)
92 | {
93 | return (string) dp.GetValue(BoundPassword);
94 | }
95 |
96 | public static void SetBoundPassword(DependencyObject dp, string value)
97 | {
98 | dp.SetValue(BoundPassword, value);
99 | }
100 |
101 | private static bool GetUpdatingPassword(DependencyObject dp)
102 | {
103 | return (bool) dp.GetValue(UpdatingPassword);
104 | }
105 |
106 | private static void SetUpdatingPassword(DependencyObject dp, bool value)
107 | {
108 | dp.SetValue(UpdatingPassword, value);
109 | }
110 | }
111 | }
--------------------------------------------------------------------------------
/Examples/FormValidationExample/Infrastructure/ValidatableViewModelBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.ComponentModel;
4 | using System.Threading.Tasks;
5 | using GalaSoft.MvvmLight;
6 | using MvvmValidation;
7 |
8 | namespace FormValidationExample.Infrastructure
9 | {
10 | public abstract class ValidatableViewModelBase : ViewModelBase, IValidatable, INotifyDataErrorInfo
11 | {
12 | protected ValidationHelper Validator { get; }
13 |
14 | private NotifyDataErrorInfoAdapter NotifyDataErrorInfoAdapter { get; }
15 |
16 | protected ValidatableViewModelBase()
17 | {
18 | Validator = new ValidationHelper();
19 |
20 | NotifyDataErrorInfoAdapter = new NotifyDataErrorInfoAdapter(Validator);
21 | NotifyDataErrorInfoAdapter.ErrorsChanged += OnErrorsChanged;
22 | }
23 |
24 | private void OnErrorsChanged(object sender, DataErrorsChangedEventArgs e)
25 | {
26 | // Notify the UI that the property has changed so that the validation error gets displayed (or removed).
27 | RaisePropertyChanged(e.PropertyName);
28 | }
29 |
30 | Task IValidatable.Validate()
31 | {
32 | return Validator.ValidateAllAsync();
33 | }
34 |
35 | #region Implementation of INotifyDataErrorInfo
36 |
37 | public IEnumerable GetErrors(string propertyName)
38 | {
39 | return NotifyDataErrorInfoAdapter.GetErrors(propertyName);
40 | }
41 |
42 | public bool HasErrors => NotifyDataErrorInfoAdapter.HasErrors;
43 |
44 | public event EventHandler ErrorsChanged
45 | {
46 | add { NotifyDataErrorInfoAdapter.ErrorsChanged += value; }
47 | remove { NotifyDataErrorInfoAdapter.ErrorsChanged -= value; }
48 | }
49 |
50 | #endregion
51 | }
52 | }
--------------------------------------------------------------------------------
/Examples/FormValidationExample/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Examples/FormValidationExample/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace FormValidationExample
4 | {
5 | ///
6 | /// Interaction logic for MainWindow.xaml
7 | ///
8 | public partial class MainWindow : Window
9 | {
10 | public MainWindow()
11 | {
12 | InitializeComponent();
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/Examples/FormValidationExample/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 | using System.Windows;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 |
9 | [assembly: AssemblyTitle("FormValidationExample")]
10 | [assembly: AssemblyDescription("")]
11 | [assembly: AssemblyConfiguration("")]
12 | [assembly: AssemblyCompany("CtrlSoft")]
13 | [assembly: AssemblyProduct("FormValidationExample")]
14 | [assembly: AssemblyCopyright("Copyright © CtrlSoft 2011")]
15 | [assembly: AssemblyTrademark("")]
16 | [assembly: AssemblyCulture("")]
17 |
18 | // Setting ComVisible to false makes the types in this assembly not visible
19 | // to COM components. If you need to access a type in this assembly from
20 | // COM, set the ComVisible attribute to true on that type.
21 |
22 | [assembly: ComVisible(false)]
23 |
24 | //In order to begin building localizable applications, set
25 | //CultureYouAreCodingWith in your .csproj file
26 | //inside a . For example, if you are using US english
27 | //in your source files, set the to en-US. Then uncomment
28 | //the NeutralResourceLanguage attribute below. Update the "en-US" in
29 | //the line below to match the UICulture setting in the project file.
30 |
31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
32 |
33 |
34 | [assembly: ThemeInfo(
35 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
36 | //(used if a resource is not found in the page,
37 | // or application resource dictionaries)
38 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
39 | //(used if a resource is not found in the page,
40 | // app, or any theme specific resource dictionaries)
41 | )]
42 |
43 |
44 | // Version information for an assembly consists of the following four values:
45 | //
46 | // Major Version
47 | // Minor Version
48 | // Build Number
49 | // Revision
50 | //
51 | // You can specify all the values or you can default the Build and Revision Numbers
52 | // by using the '*' as shown below:
53 | // [assembly: AssemblyVersion("1.0.*")]
54 |
55 | [assembly: AssemblyVersion("1.0.0.0")]
56 | [assembly: AssemblyFileVersion("1.0.0.0")]
--------------------------------------------------------------------------------
/Examples/FormValidationExample/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.34003
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace FormValidationExample.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("FormValidationExample.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/Examples/FormValidationExample/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/Examples/FormValidationExample/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace FormValidationExample.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Examples/FormValidationExample/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Examples/FormValidationExample/Services/IUserRegistrationService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace FormValidationExample.Services
4 | {
5 | public interface IUserRegistrationService
6 | {
7 | IObservable IsUserNameAvailable(string userName);
8 | }
9 | }
--------------------------------------------------------------------------------
/Examples/FormValidationExample/Services/UserRegistrationService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Reactive.Linq;
4 |
5 | namespace FormValidationExample.Services
6 | {
7 | public class UserRegistrationService : IUserRegistrationService
8 | {
9 | private bool lastResult = true;
10 | private readonly IDictionary resultCache = new Dictionary();
11 |
12 | public IObservable IsUserNameAvailable(string userName)
13 | {
14 | bool isNameAvailable;
15 |
16 | if (!resultCache.TryGetValue(userName, out isNameAvailable))
17 | {
18 | isNameAvailable = lastResult = !lastResult;
19 | resultCache.Add(userName, isNameAvailable);
20 | }
21 |
22 | // Return random result with a delay to simulate server communication
23 | return Observable.Return(isNameAvailable).Delay(TimeSpan.FromMilliseconds(500));
24 | }
25 | }
26 | }
--------------------------------------------------------------------------------
/Examples/FormValidationExample/View/FormControl.xaml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
45 |
46 |
49 |
50 |
55 |
56 |
60 |
61 |
66 |
67 |
71 |
72 |
77 |
78 |
82 |
83 |
89 |
90 |
96 |
97 |
104 |
105 |
110 |
111 |
116 |
117 |
123 |
124 |
128 |
129 |
136 |
137 |
138 |
--------------------------------------------------------------------------------
/Examples/FormValidationExample/View/FormControl.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Controls;
2 |
3 | namespace FormValidationExample.View
4 | {
5 | public partial class FormControl : UserControl
6 | {
7 | public FormControl()
8 | {
9 | InitializeComponent();
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/Examples/FormValidationExample/View/InterestSelectorView.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
15 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
27 |
28 |
36 |
37 |
38 |
39 |
40 |
41 |
43 |
44 |
--------------------------------------------------------------------------------
/Examples/FormValidationExample/View/InterestSelectorView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Controls;
2 |
3 | namespace FormValidationExample.View
4 | {
5 | public partial class InterestSelectorView : UserControl
6 | {
7 | public InterestSelectorView()
8 | {
9 | InitializeComponent();
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/Examples/FormValidationExample/View/MainView.xaml:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
17 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
29 |
30 |
31 | Visible
32 |
33 |
34 |
35 |
37 |
39 |
41 |
42 |
43 |
44 |
45 |
46 |
48 |
49 |
50 | Visible
51 |
52 |
53 |
54 |
57 |
59 |
61 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
72 |
73 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
105 |
106 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
128 |
132 |
133 |
134 |
135 |
141 |
144 |
145 |
146 |
150 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
--------------------------------------------------------------------------------
/Examples/FormValidationExample/View/MainView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Controls;
2 | using FormValidationExample.Services;
3 | using FormValidationExample.ViewModel;
4 |
5 | namespace FormValidationExample.View
6 | {
7 | public partial class MainView : UserControl
8 | {
9 | public MainView()
10 | {
11 | InitializeComponent();
12 |
13 | DataContext = new MainViewModel(new UserRegistrationService());
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/Examples/FormValidationExample/ViewModel/InterestItemViewModel.cs:
--------------------------------------------------------------------------------
1 | using GalaSoft.MvvmLight;
2 |
3 | namespace FormValidationExample.ViewModel
4 | {
5 | public class InterestItemViewModel : ViewModelBase
6 | {
7 | private bool isSelected;
8 |
9 | public InterestItemViewModel(string name, InterestSelectorViewModel parentSelector)
10 | {
11 | Name = name;
12 | ParentSelector = parentSelector;
13 | }
14 |
15 | public string Name { get; private set; }
16 | private InterestSelectorViewModel ParentSelector { get; set; }
17 |
18 | public bool IsSelected
19 | {
20 | get { return isSelected; }
21 | set
22 | {
23 | isSelected = value;
24 | RaisePropertyChanged("IsSelected");
25 | ParentSelector.OnInterestSelectionChanged();
26 | }
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/Examples/FormValidationExample/ViewModel/InterestSelectorViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Collections.ObjectModel;
4 | using System.Linq;
5 | using FormValidationExample.Infrastructure;
6 | using MvvmValidation;
7 |
8 | namespace FormValidationExample.ViewModel
9 | {
10 | public class InterestSelectorViewModel : ValidatableViewModelBase
11 | {
12 | public InterestSelectorViewModel()
13 | {
14 | Interests = new ObservableCollection
15 | {
16 | new InterestItemViewModel("Music", this),
17 | new InterestItemViewModel("Movies", this),
18 | new InterestItemViewModel("Sports", this),
19 | new InterestItemViewModel("Shopping", this),
20 | new InterestItemViewModel("Hunting", this),
21 | new InterestItemViewModel("Books", this),
22 | new InterestItemViewModel("Physics", this),
23 | new InterestItemViewModel("Comics", this)
24 | };
25 |
26 | ConfigureValidationRules();
27 | }
28 |
29 | public IEnumerable Interests { get; private set; }
30 |
31 | public IEnumerable SelectedInterests
32 | {
33 | get { return Interests.Where(i => i.IsSelected).ToArray(); }
34 | }
35 |
36 | private void ConfigureValidationRules()
37 | {
38 | Validator.AddRule(
39 | () => RuleResult.Assert(SelectedInterests.Count() >= 3, "Please select at least 3 interests"));
40 | }
41 |
42 | public void OnInterestSelectionChanged()
43 | {
44 | OnSelectedInterestsChanged();
45 | }
46 |
47 | #region SelectedInterestsChanged Event
48 |
49 | public event EventHandler SelectedInterestsChanged;
50 |
51 | private void OnSelectedInterestsChanged()
52 | {
53 | EventHandler handler = SelectedInterestsChanged;
54 | if (handler != null)
55 | {
56 | handler(this, EventArgs.Empty);
57 | }
58 | }
59 |
60 | #endregion
61 | }
62 | }
--------------------------------------------------------------------------------
/Examples/FormValidationExample/ViewModel/MainViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Reactive.Threading.Tasks;
4 | using System.Text.RegularExpressions;
5 | using System.Threading.Tasks;
6 | using System.Windows.Input;
7 | using FormValidationExample.Infrastructure;
8 | using FormValidationExample.Services;
9 | using GalaSoft.MvvmLight.Command;
10 | using MvvmValidation;
11 |
12 | namespace FormValidationExample.ViewModel
13 | {
14 | public class MainViewModel : ValidatableViewModelBase
15 | {
16 | private string email;
17 | private readonly NameInfo nameInfo = new NameInfo();
18 | private bool? isValid;
19 | private string password;
20 | private string passwordConfirmation;
21 | private string userName;
22 | private string validationErrorsString;
23 |
24 | public MainViewModel(IUserRegistrationService userRegistrationService)
25 | {
26 | UserRegistrationService = userRegistrationService;
27 |
28 | InterestSelectorViewModel = new InterestSelectorViewModel();
29 | InterestSelectorViewModel.SelectedInterestsChanged += OnSelectedInterestsChanged;
30 |
31 | ValidateCommand = new RelayCommand(Validate);
32 |
33 | ConfigureValidationRules();
34 | Validator.ResultChanged += OnValidationResultChanged;
35 | }
36 |
37 | private IUserRegistrationService UserRegistrationService { get; set; }
38 |
39 | public ICommand ValidateCommand { get; private set; }
40 |
41 | public string UserName
42 | {
43 | get { return userName; }
44 | set
45 | {
46 | userName = value;
47 | RaisePropertyChanged(nameof(UserName));
48 | Validator.ValidateAsync(nameof(UserName));
49 | }
50 | }
51 |
52 | public string FirstName
53 | {
54 | get { return nameInfo.FirstName; }
55 | set
56 | {
57 | nameInfo.FirstName = value;
58 | RaisePropertyChanged(nameof(FirstName));
59 | Validator.Validate(nameof(FirstName));
60 | }
61 | }
62 |
63 | public string LastName
64 | {
65 | get { return nameInfo.LastName; }
66 | set
67 | {
68 | nameInfo.LastName = value;
69 | RaisePropertyChanged(nameof(LastName));
70 | Validator.Validate(nameof(LastName));
71 | }
72 | }
73 |
74 | public string Email
75 | {
76 | get { return email; }
77 | set
78 | {
79 | email = value;
80 | RaisePropertyChanged(nameof(Email));
81 | Validator.Validate(nameof(Email));
82 | }
83 | }
84 |
85 | public string Password
86 | {
87 | get { return password; }
88 | set
89 | {
90 | password = value;
91 | RaisePropertyChanged(nameof(Password));
92 | Validator.Validate(nameof(Password));
93 | }
94 | }
95 |
96 | public string PasswordConfirmation
97 | {
98 | get { return passwordConfirmation; }
99 | set
100 | {
101 | passwordConfirmation = value;
102 | RaisePropertyChanged(nameof(PasswordConfirmation));
103 | Validator.Validate(nameof(PasswordConfirmation));
104 | }
105 | }
106 |
107 | public string ValidationErrorsString
108 | {
109 | get { return validationErrorsString; }
110 | private set
111 | {
112 | validationErrorsString = value;
113 | RaisePropertyChanged(nameof(ValidationErrorsString));
114 | }
115 | }
116 |
117 | public bool? IsValid
118 | {
119 | get { return isValid; }
120 | private set
121 | {
122 | isValid = value;
123 | RaisePropertyChanged(nameof(IsValid));
124 | }
125 | }
126 |
127 | public InterestSelectorViewModel InterestSelectorViewModel { get; private set; }
128 |
129 | private void ConfigureValidationRules()
130 | {
131 | Validator.AddRequiredRule(() => UserName, "User Name is required");
132 |
133 | Validator.AddAsyncRule(nameof(UserName),
134 | async () =>
135 | {
136 | var isAvailable = await UserRegistrationService.IsUserNameAvailable(UserName).ToTask();
137 |
138 | return RuleResult.Assert(isAvailable,
139 | string.Format("User Name {0} is taken. Please choose a different one.", UserName));
140 | });
141 |
142 | Validator.AddRequiredRule(() => FirstName, "First Name is required");
143 |
144 | Validator.AddRequiredRule(() => LastName, "Last Name is required");
145 |
146 | Validator.AddRequiredRule(() => Email, "Email is required");
147 |
148 | Validator.AddRule(nameof(Email),
149 | () =>
150 | {
151 | const string regexPattern =
152 | @"^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$";
153 | return RuleResult.Assert(Regex.IsMatch(Email, regexPattern),
154 | "Email must by a valid email address");
155 | });
156 |
157 | Validator.AddRequiredRule(() => Password, "Password is required");
158 |
159 | Validator.AddRule(nameof(Password),
160 | () => RuleResult.Assert(Password.Length >= 6,
161 | "Password must contain at least 6 characters"));
162 |
163 | Validator.AddRule(nameof(Password),
164 | () => RuleResult.Assert((!Password.All(char.IsLower) &&
165 | !Password.All(char.IsUpper) &&
166 | !Password.All(char.IsDigit)),
167 | "Password must contain both lower case and upper case letters"));
168 |
169 | Validator.AddRule(nameof(Password),
170 | () => RuleResult.Assert(Password.Any(char.IsDigit),
171 | "Password must contain at least one digit"));
172 |
173 | Validator.AddRule(nameof(PasswordConfirmation),
174 | () =>
175 | {
176 | if (!string.IsNullOrEmpty(Password) && string.IsNullOrEmpty(PasswordConfirmation))
177 | {
178 | return RuleResult.Invalid("Please confirm password");
179 | }
180 |
181 | return RuleResult.Valid();
182 | });
183 |
184 | Validator.AddRule(nameof(Password),
185 | nameof(PasswordConfirmation),
186 | () =>
187 | {
188 | if (!string.IsNullOrEmpty(Password) && !string.IsNullOrEmpty(PasswordConfirmation))
189 | {
190 | return RuleResult.Assert(Password == PasswordConfirmation, "Passwords do not match");
191 | }
192 |
193 | return RuleResult.Valid();
194 | });
195 |
196 | Validator.AddChildValidatable(() => InterestSelectorViewModel);
197 | }
198 |
199 | private void OnSelectedInterestsChanged(object sender, EventArgs e)
200 | {
201 | var currentState = Validator.GetResult(nameof(InterestSelectorViewModel));
202 |
203 | if (!currentState.IsValid)
204 | {
205 | Validator.ValidateAsync(nameof(InterestSelectorViewModel));
206 | }
207 | }
208 |
209 | private async void Validate()
210 | {
211 | await ValidateAsync();
212 | }
213 |
214 | private async Task ValidateAsync()
215 | {
216 | var result = await Validator.ValidateAllAsync();
217 |
218 | UpdateValidationSummary(result);
219 | }
220 |
221 | private void OnValidationResultChanged(object sender, ValidationResultChangedEventArgs e)
222 | {
223 | if (!IsValid.GetValueOrDefault(true))
224 | {
225 | ValidationResult validationResult = Validator.GetResult();
226 |
227 | UpdateValidationSummary(validationResult);
228 | }
229 | }
230 |
231 | private void UpdateValidationSummary(ValidationResult validationResult)
232 | {
233 | IsValid = validationResult.IsValid;
234 | ValidationErrorsString = validationResult.ToString();
235 | }
236 | }
237 | }
--------------------------------------------------------------------------------
/Examples/FormValidationExample/ViewModel/NameInfo.cs:
--------------------------------------------------------------------------------
1 | namespace FormValidationExample.ViewModel
2 | {
3 | public class NameInfo
4 | {
5 | public NameInfo()
6 | {
7 | }
8 |
9 | public NameInfo(string firstName, string lastName)
10 | {
11 | FirstName = firstName;
12 | LastName = lastName;
13 | }
14 |
15 | public string FirstName { get; set; }
16 | public string LastName { get; set; }
17 | }
18 | }
--------------------------------------------------------------------------------
/Examples/FormValidationExample/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Examples/FormValidationExample/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Examples/Lib/.NETFramework/Microsoft.Expression.Interactions.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pglazkov/MvvmValidation/5fd89911f1cfe8fe3bd7912481deb826c16e236b/Examples/Lib/.NETFramework/Microsoft.Expression.Interactions.dll
--------------------------------------------------------------------------------
/Examples/Lib/.NETFramework/System.Windows.Interactivity.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pglazkov/MvvmValidation/5fd89911f1cfe8fe3bd7912481deb826c16e236b/Examples/Lib/.NETFramework/System.Windows.Interactivity.dll
--------------------------------------------------------------------------------
/Examples/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pglazkov/MvvmValidation/5fd89911f1cfe8fe3bd7912481deb826c16e236b/Examples/screenshot.png
--------------------------------------------------------------------------------
/Key.snk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pglazkov/MvvmValidation/5fd89911f1cfe8fe3bd7912481deb826c16e236b/Key.snk
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Pavlo Glazkov
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/MvvmValidation.Portable/IAsyncValidationRule.cs:
--------------------------------------------------------------------------------
1 | namespace MvvmValidation
2 | {
3 | ///
4 | /// Represents an asynchronous validation rule.
5 | ///
6 | public interface IAsyncValidationRule : IValidationRule
7 | {
8 | }
9 | }
--------------------------------------------------------------------------------
/MvvmValidation.Portable/IValidatable.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using JetBrains.Annotations;
3 |
4 | namespace MvvmValidation
5 | {
6 | ///
7 | /// Represents an object that can be validated.
8 | ///
9 | public interface IValidatable
10 | {
11 | ///
12 | /// Validates the object asyncrhonously.
13 | ///
14 | /// Task that represents the validation operation.
15 | [NotNull]
16 | Task Validate();
17 | }
18 | }
--------------------------------------------------------------------------------
/MvvmValidation.Portable/IValidationResultFormatter.cs:
--------------------------------------------------------------------------------
1 | using JetBrains.Annotations;
2 |
3 | namespace MvvmValidation
4 | {
5 | ///
6 | /// Represents a formatter that can be used to format an instance of to a string.
7 | ///
8 | public interface IValidationResultFormatter
9 | {
10 | ///
11 | /// Converts the specified validation result object to a string.
12 | ///
13 | /// The validation result to format.
14 | /// A string representation of
15 | [NotNull]
16 | string Format([NotNull] ValidationResult validationResult);
17 | }
18 | }
--------------------------------------------------------------------------------
/MvvmValidation.Portable/IValidationRule.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using JetBrains.Annotations;
3 |
4 | namespace MvvmValidation
5 | {
6 | ///
7 | /// Represents a validation rule.
8 | ///
9 | public interface IValidationRule
10 | {
11 | ///
12 | /// Allows changing the rule settings.
13 | ///
14 | /// A function that accepts an instance of that contains settings for this rule.
15 | /// The same fule instance (allows for "fluent" interface with chained calls).
16 | [NotNull]
17 | IValidationRule WithSettings([NotNull] Action setSettingsDelegate);
18 | }
19 | }
--------------------------------------------------------------------------------
/MvvmValidation.Portable/Internal/AutoToggle.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace MvvmValidation.Internal
8 | {
9 | internal class AutoToggle
10 | {
11 | private readonly bool defaultValue;
12 | private int refCount = 0;
13 |
14 | public AutoToggle(bool defaultValue)
15 | {
16 | this.defaultValue = defaultValue;
17 | }
18 |
19 | public bool Value => refCount > 0 ? !defaultValue : defaultValue;
20 |
21 | public IDisposable Toggle()
22 | {
23 | return new Lock(this);
24 | }
25 |
26 | private class Lock : IDisposable
27 | {
28 | private readonly AutoToggle toggle;
29 |
30 | public Lock(AutoToggle toggle)
31 | {
32 | this.toggle = toggle;
33 | System.Threading.Interlocked.Increment(ref toggle.refCount);
34 | }
35 |
36 | public void Dispose()
37 | {
38 | System.Threading.Interlocked.Decrement(ref toggle.refCount);
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/MvvmValidation.Portable/Internal/CallerInfoAttributes.cs:
--------------------------------------------------------------------------------
1 | //// Decompiled with JetBrains decompiler
2 | //// Type: System.Runtime.CompilerServices.CallerMemberNameAttribute
3 | //// Assembly: System.Runtime, Version=2.5.19.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
4 | //// MVID: E26714E1-CF4B-4642-B34B-759C8FD62E7B
5 | //// Assembly location: D:\Work\GIT\Projects\Applications\EDiscovery\lib.ext\Microsoft.Bcl\lib\portable-net40+sl5+win8+wp8\System.Runtime.dll
6 |
7 | //using System;
8 |
9 | //// ReSharper disable CheckNamespace
10 | //namespace System.Runtime.CompilerServices
11 | //// ReSharper restore CheckNamespace
12 | //{
13 | // ///
14 | // /// Allows you to obtain the method or property name of the caller to the method.
15 | // ///
16 | // ///
17 | // [AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
18 | // public sealed class CallerMemberNameAttribute : Attribute
19 | // {
20 | // }
21 |
22 | // ///
23 | // /// Allows you to obtain the full path of the source file that contains the caller.
24 | // /// This is the file path at the time of compile.
25 | // ///
26 | // ///
27 | // [AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
28 | // public sealed class CallerFilePathAttribute : Attribute
29 | // {
30 | // }
31 |
32 | // ///
33 | // /// Allows you to obtain the line number in the source file at which the method is called.
34 | // ///
35 | // ///
36 | // [AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
37 | // public sealed class CallerLineNumberAttribute : Attribute
38 | // {
39 | // }
40 | //}
41 |
42 |
--------------------------------------------------------------------------------
/MvvmValidation.Portable/Internal/CollectionUtils.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 |
4 | namespace MvvmValidation.Internal
5 | {
6 | internal static class CollectionUtils
7 | {
8 | public static bool ItemsEqual(this IEnumerable collection1, IEnumerable collection2)
9 | {
10 | if (collection1 == null && collection2 == null)
11 | {
12 | return true;
13 | }
14 |
15 | if (collection1 == null || collection2 == null)
16 | {
17 | return false;
18 | }
19 |
20 | if (collection1.Count() != collection2.Count())
21 | {
22 | return false;
23 | }
24 |
25 | foreach (var item in collection1)
26 | {
27 | if (!collection2.Contains(item))
28 | {
29 | return false;
30 | }
31 | }
32 |
33 | return true;
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/MvvmValidation.Portable/Internal/DelegateDisposable.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MvvmValidation.Internal
4 | {
5 | internal sealed class DelegateDisposable : IDisposable
6 | {
7 | public DelegateDisposable(Action restoreStateDelegate)
8 | {
9 | RestoreStateDelegate = restoreStateDelegate;
10 | }
11 |
12 | private Action RestoreStateDelegate { get; set; }
13 |
14 | #region IDisposable Members
15 |
16 | public void Dispose()
17 | {
18 | RestoreStateDelegate();
19 | }
20 |
21 | #endregion
22 | }
23 | }
--------------------------------------------------------------------------------
/MvvmValidation.Portable/Internal/ExceptionUtils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 |
6 | namespace MvvmValidation.Internal
7 | {
8 | internal static class ExceptionUtils
9 | {
10 | public static IEnumerable UnwrapExceptions(Exception exception)
11 | {
12 | var loadException = exception as ReflectionTypeLoadException;
13 | if (loadException != null)
14 | {
15 | return loadException.LoaderExceptions.SelectMany(UnwrapExceptions);
16 | }
17 |
18 | if (exception is TargetInvocationException)
19 | {
20 | return UnwrapExceptions(exception.InnerException);
21 | }
22 |
23 | var aggregateException = exception as AggregateException;
24 | if (aggregateException != null)
25 | {
26 | return aggregateException.InnerExceptions.SelectMany(UnwrapExceptions);
27 | }
28 |
29 | var validationException = exception as ValidationException;
30 | if (validationException != null)
31 | {
32 | return UnwrapExceptions(validationException.InnerException);
33 | }
34 |
35 | if (exception.GetType() == typeof(Exception) && exception.InnerException != null)
36 | {
37 | return UnwrapExceptions(exception.InnerException);
38 | }
39 |
40 | return new[] {exception};
41 | }
42 |
43 | public static Exception UnwrapException(Exception exception)
44 | {
45 | var unwrappedExceptions = UnwrapExceptions(exception).ToArray();
46 |
47 | if (unwrappedExceptions.Length > 1)
48 | {
49 | return new AggregateException(unwrappedExceptions);
50 | }
51 |
52 | return unwrappedExceptions[0];
53 | }
54 | }
55 | }
--------------------------------------------------------------------------------
/MvvmValidation.Portable/Internal/GenericValidationTarget.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace MvvmValidation.Internal
5 | {
6 | internal class GenericValidationTarget : IValidationTarget, IEquatable
7 | {
8 | public GenericValidationTarget(object targetId)
9 | {
10 | Guard.NotNull(targetId, nameof(targetId));
11 |
12 | TargetId = targetId;
13 | }
14 |
15 | public object TargetId { get; set; }
16 |
17 | #region IEquatable Members
18 |
19 | public bool Equals(GenericValidationTarget other)
20 | {
21 | if (ReferenceEquals(null, other))
22 | {
23 | return false;
24 | }
25 | if (ReferenceEquals(this, other))
26 | {
27 | return true;
28 | }
29 | return Equals(other.TargetId, TargetId);
30 | }
31 |
32 | #endregion
33 |
34 | #region IValidationTarget Members
35 |
36 | public IEnumerable