Mercurial > silverbladetech
changeset 50:64f19743cfd6
Initial load for Silverlight Validation
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightValidation.sln Wed Apr 18 22:28:46 2012 +0100 @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SilverlightValidation", "SilverlightValidation\SilverlightValidation.csproj", "{0C1CC1FC-915A-4428-8952-CDC79EABC3F4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0C1CC1FC-915A-4428-8952-CDC79EABC3F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0C1CC1FC-915A-4428-8952-CDC79EABC3F4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0C1CC1FC-915A-4428-8952-CDC79EABC3F4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0C1CC1FC-915A-4428-8952-CDC79EABC3F4}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightValidation/App.xaml Wed Apr 18 22:28:46 2012 +0100 @@ -0,0 +1,3 @@ +<Application x:Class="SilverlightValidation.App" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" />
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightValidation/App.xaml.cs Wed Apr 18 22:28:46 2012 +0100 @@ -0,0 +1,59 @@ +using System; +using System.Windows; + +namespace SilverlightValidation +{ + public partial class App : Application + { + + public App() + { + this.Startup += this.Application_Startup; + this.Exit += this.Application_Exit; + this.UnhandledException += this.Application_UnhandledException; + + InitializeComponent(); + } + + private void Application_Startup(object sender, StartupEventArgs e) + { + this.RootVisual = new UserView(); + } + + private void Application_Exit(object sender, EventArgs e) + { + + } + + private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e) + { + // If the app is running outside of the debugger then report the exception using + // the browser's exception mechanism. On IE this will display it a yellow alert + // icon in the status bar and Firefox will display a script error. + if (!System.Diagnostics.Debugger.IsAttached) + { + + // NOTE: This will allow the application to continue running after an exception has been thrown + // but not handled. + // For production applications this error handling should be replaced with something that will + // report the error to the website and stop the application. + e.Handled = true; + Deployment.Current.Dispatcher.BeginInvoke(delegate { ReportErrorToDOM(e); }); + } + } + + private void ReportErrorToDOM(ApplicationUnhandledExceptionEventArgs e) + { + try + { + string errorMsg = e.ExceptionObject.Message + e.ExceptionObject.StackTrace; + errorMsg = errorMsg.Replace('"', '\'').Replace("\r\n", @"\n"); + + System.Windows.Browser.HtmlPage.Window.Eval("throw new Error(\"Unhandled Error in Silverlight Application " + errorMsg + "\");"); + } + catch (Exception) + { + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightValidation/Properties/AppManifest.xml Wed Apr 18 22:28:46 2012 +0100 @@ -0,0 +1,6 @@ +<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" +> + <Deployment.Parts> + </Deployment.Parts> +</Deployment>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightValidation/Properties/AssemblyInfo.cs Wed Apr 18 22:28:46 2012 +0100 @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SilverlightValidation")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SilverlightValidation")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("3f5a4c47-8fbd-4568-8728-e26ee6a51945")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightValidation/RelayCommand.cs Wed Apr 18 22:28:46 2012 +0100 @@ -0,0 +1,41 @@ +using System; +using System.Windows.Input; + +namespace SilverlightValidation +{ + public class RelayCommand : ICommand + { + public event EventHandler CanExecuteChanged; + + readonly Action<object> _execute; + readonly Predicate<object> _canExecute; + + public RelayCommand(Action<object> execute, + Predicate<object> canExecute = null) + { + if (execute == null) throw new ArgumentNullException("execute"); + + _execute = execute; + _canExecute = canExecute; + } + + + public void UpdateCanExecuteCommand() + { + if (CanExecuteChanged != null) + CanExecuteChanged(this, new EventArgs()); + } + + + public bool CanExecute(object parameter) + { + return _canExecute == null || _canExecute(parameter); + } + + + public void Execute(object parameter) + { + _execute(parameter); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightValidation/SilverlightValidation.csproj Wed Apr 18 22:28:46 2012 +0100 @@ -0,0 +1,122 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProductVersion>8.0.50727</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{0C1CC1FC-915A-4428-8952-CDC79EABC3F4}</ProjectGuid> + <ProjectTypeGuids>{A1591282-1198-4647-A2B1-27E5FF5F6F3B};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids> + <OutputType>Library</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>SilverlightValidation</RootNamespace> + <AssemblyName>SilverlightValidation</AssemblyName> + <TargetFrameworkIdentifier>Silverlight</TargetFrameworkIdentifier> + <TargetFrameworkVersion>v5.0</TargetFrameworkVersion> + <SilverlightVersion>$(TargetFrameworkVersion)</SilverlightVersion> + <SilverlightApplication>true</SilverlightApplication> + <SupportedCultures> + </SupportedCultures> + <XapOutputs>true</XapOutputs> + <GenerateSilverlightManifest>true</GenerateSilverlightManifest> + <XapFilename>SilverlightValidation.xap</XapFilename> + <SilverlightManifestTemplate>Properties\AppManifest.xml</SilverlightManifestTemplate> + <SilverlightAppEntry>SilverlightValidation.App</SilverlightAppEntry> + <TestPageFileName>SilverlightValidationTestPage.html</TestPageFileName> + <CreateTestPage>true</CreateTestPage> + <ValidateXaml>true</ValidateXaml> + <EnableOutOfBrowser>false</EnableOutOfBrowser> + <OutOfBrowserSettingsFile>Properties\OutOfBrowserSettings.xml</OutOfBrowserSettingsFile> + <UsePlatformExtensions>false</UsePlatformExtensions> + <ThrowErrorsInValidation>true</ThrowErrorsInValidation> + <LinkedServerProject> + </LinkedServerProject> + </PropertyGroup> + <!-- This property group is only here to support building this project using the + MSBuild 3.5 toolset. In order to work correctly with this older toolset, it needs + to set the TargetFrameworkVersion to v3.5 --> + <PropertyGroup Condition="'$(MSBuildToolsVersion)' == '3.5'"> + <TargetFrameworkVersion>v3.5</TargetFrameworkVersion> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>Bin\Debug</OutputPath> + <DefineConstants>DEBUG;TRACE;SILVERLIGHT</DefineConstants> + <NoStdLib>true</NoStdLib> + <NoConfig>true</NoConfig> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>Bin\Release</OutputPath> + <DefineConstants>TRACE;SILVERLIGHT</DefineConstants> + <NoStdLib>true</NoStdLib> + <NoConfig>true</NoConfig> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="FluentValidation"> + <HintPath>..\Libs\FluentValidation.dll</HintPath> + </Reference> + <Reference Include="mscorlib" /> + <Reference Include="System.Windows" /> + <Reference Include="system" /> + <Reference Include="System.Core" /> + <Reference Include="System.Windows.Controls, Version=5.0.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> + <HintPath>..\Libs\System.Windows.Controls.dll</HintPath> + </Reference> + <Reference Include="System.Windows.Controls.Data.Input, Version=5.0.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> + <HintPath>..\Libs\System.Windows.Controls.Data.Input.dll</HintPath> + </Reference> + <Reference Include="System.Xml" /> + <Reference Include="System.Windows.Browser" /> + </ItemGroup> + <ItemGroup> + <Compile Include="App.xaml.cs"> + <DependentUpon>App.xaml</DependentUpon> + </Compile> + <Compile Include="Properties\AssemblyInfo.cs" /> + <Compile Include="RelayCommand.cs" /> + <Compile Include="UserModel.cs" /> + <Compile Include="UserModelValidator.cs" /> + <Compile Include="UserViewModel.cs" /> + <Compile Include="ViewModelBase.cs" /> + <Compile Include="UserView.xaml.cs"> + <DependentUpon>UserView.xaml</DependentUpon> + </Compile> + </ItemGroup> + <ItemGroup> + <ApplicationDefinition Include="App.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </ApplicationDefinition> + <Page Include="UserView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + </ItemGroup> + <ItemGroup> + <None Include="Properties\AppManifest.xml" /> + </ItemGroup> + <ItemGroup /> + <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Silverlight\$(SilverlightVersion)\Microsoft.Silverlight.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> + <ProjectExtensions> + <VisualStudio> + <FlavorProperties GUID="{A1591282-1198-4647-A2B1-27E5FF5F6F3B}"> + <SilverlightProjectProperties /> + </FlavorProperties> + </VisualStudio> + </ProjectExtensions> +</Project> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightValidation/UserModel.cs Wed Apr 18 22:28:46 2012 +0100 @@ -0,0 +1,23 @@ +using System; + +namespace SilverlightValidation +{ + public interface ICloneable<T> + { + T Clone(); + } + + public class UserModel : IUserModel, ICloneable<UserModel> + { + public string Username { get; set; } + public string Email { get; set; } + public string Password { get; set; } + public DateTime DateOfBirth { get; set; } + public string Description { get; set; } + + public UserModel Clone() + { + return (UserModel) this.MemberwiseClone(); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightValidation/UserModelValidator.cs Wed Apr 18 22:28:46 2012 +0100 @@ -0,0 +1,32 @@ +using System; +using FluentValidation; + +namespace SilverlightValidation +{ + public class UserModelValidator : AbstractValidator<IUserModel> + { + public UserModelValidator() + { + RuleFor(x => x.Username) + .NotEmpty() + .WithMessage("Username cannot be blank."); + + RuleFor(x => x.Password) + .NotEmpty() + .WithMessage("Password cannot be blank."); + + RuleFor(x => x.Email) + .EmailAddress() + .WithMessage("Email is required."); + + RuleFor(x => x.DateOfBirth) + .Must(BeAValidDateOfBirth) + .WithMessage("Date of birth must be within the last 100 years."); + } + + private bool BeAValidDateOfBirth(DateTime dateOfBirth) + { + return (dateOfBirth < DateTime.Today) && (dateOfBirth > DateTime.Today.AddYears(-100)); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightValidation/UserView.xaml Wed Apr 18 22:28:46 2012 +0100 @@ -0,0 +1,109 @@ +<UserControl x:Class="SilverlightValidation.UserView" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" + d:DesignHeight="350" + d:DesignWidth="400" + mc:Ignorable="d"> + + <Grid x:Name="LayoutRoot" Background="White"> + + <Grid.RowDefinitions> + <RowDefinition Height="30" /> + <RowDefinition Height="30" /> + <RowDefinition Height="30" /> + <RowDefinition Height="30" /> + <RowDefinition Height="30" /> + <RowDefinition Height="30" /> + <RowDefinition Height="50" /> + <RowDefinition Height="120" /> + </Grid.RowDefinitions> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="*" /> + <ColumnDefinition Width="100" /> + <ColumnDefinition Width="300" /> + <ColumnDefinition Width="*" /> + </Grid.ColumnDefinitions> + + <Grid.Resources> + <Style TargetType="TextBlock"> + <Setter Property="Height" Value="18" /> + <Setter Property="FontFamily" Value="Segoe UI Light" /> + <Setter Property="FontSize" Value="14" /> + <Setter Property="VerticalAlignment" Value="Center" /> + </Style> + <Style TargetType="TextBox"> + <Setter Property="FontFamily" Value="Segoe UI Light" /> + <Setter Property="FontSize" Value="14" /> + <Setter Property="Height" Value="24" /> + <Setter Property="VerticalAlignment" Value="Center" /> + </Style> + <Style TargetType="sdk:DatePicker"> + <Setter Property="FontSize" Value="12" /> + <Setter Property="FontFamily" Value="Segoe UI Light" /> + <Setter Property="Height" Value="24" /> + </Style> + <Style TargetType="Button"> + <Setter Property="Height" Value="22" /> + <Setter Property="Margin" Value="5,0,0,0" /> + <Setter Property="VerticalAlignment" Value="Center" /> + <Setter Property="Width" Value="60" /> + </Style> + </Grid.Resources> + + <TextBlock Grid.Row="1" + Grid.Column="1" + Text="Username:" /> + <TextBlock Grid.Row="2" + Grid.Column="1" + Text="Password:" /> + <TextBlock Grid.Row="3" + Grid.Column="1" + Text="Email:" /> + <TextBlock Grid.Row="4" + Grid.Column="1" + Text="Date of Birth:" /> + <TextBlock Grid.Row="5" + Grid.Column="1" + Text="Description:" /> + + <TextBox Grid.Row="1" + Grid.Column="2" + Text="{Binding Username, + Mode=TwoWay, + NotifyOnValidationError=True}" /> + <TextBox Grid.Row="2" + Grid.Column="2" + Text="{Binding Password, + Mode=TwoWay, + NotifyOnValidationError=True}" /> + <TextBox Grid.Row="3" + Grid.Column="2" + Text="{Binding Email, + Mode=TwoWay, + NotifyOnValidationError=True}" /> + + <sdk:DatePicker Grid.Row="4" + Grid.Column="2" + SelectedDate="{Binding DateOfBirth, + Mode=TwoWay, + NotifyOnValidationError=True}" /> + + <TextBox Grid.Row="5" + Grid.Column="2" + Text="{Binding Description}" /> + + <StackPanel Grid.Row="6" + Grid.Column="2" + HorizontalAlignment="Right" + Orientation="Horizontal"> + <Button Command="{Binding OkCommand}" Content="OK" /> + <Button Command="{Binding CancelCommand}" Content="Cancel" /> + </StackPanel> + + <sdk:ValidationSummary Grid.Row="7" Grid.Column="2" /> + + </Grid> +</UserControl>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightValidation/UserView.xaml.cs Wed Apr 18 22:28:46 2012 +0100 @@ -0,0 +1,15 @@ +using System.Windows.Browser; + +namespace SilverlightValidation +{ + public partial class UserView + { + public UserView() + { + InitializeComponent(); + HtmlPage.Document.SetProperty("title", "Silverlight Validation"); + + this.DataContext = new UserViewModel(new UserModelValidator()); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightValidation/UserViewModel.cs Wed Apr 18 22:28:46 2012 +0100 @@ -0,0 +1,194 @@ +using System; +using System.ComponentModel; +using System.Linq; +using System.Windows; +using System.Windows.Input; +using FluentValidation; + +namespace SilverlightValidation +{ + public interface IUserModel + { + string Username { get; set; } + string Email { get; set; } + string Password { get; set; } + DateTime DateOfBirth { get; set; } + string Description { get; set; } + } + + public interface IUserViewModel + { + ICommand OkCommand { get; set; } + ICommand CancelCommand { get; set; } + } + + public class UserViewModel : ViewModelBase, IUserViewModel, IUserModel, IEditableObject + { + #region Fields + + private readonly UserModelValidator _validator; + private UserModel _data; + private UserModel _backup; + private bool _isDirty; + + #endregion + + #region Constructor + + public UserViewModel(UserModelValidator validator) + { + _validator = validator; + + OkCommand = new RelayCommand(OkCommandExecute, OkCommandCanExecute); + CancelCommand = new RelayCommand(CancelCommandExecute, CancelCommandCanExecute); + + ResetModels(); + + _backup = _data; + } + + #endregion + + private void ResetModels() + { + _backup = new UserModel(); + _data = new UserModel(); + } + + private void RequeryAllCommandsCanExecute() + { + + //this.OkCommand.(); + //this.CancelCommand(); + } + + #region Property + + private const string UsernameProperty = "Username"; + public string Username + { + get { return _data.Username; } + set + { + if (_data.Username != value) { _data.Username = value; RaisePropertyChanged(UsernameProperty); } + ClearError(UsernameProperty); + var validationResult = _validator.Validate(this, UsernameProperty); + if (!validationResult.IsValid) + validationResult.Errors.ToList().ForEach(x => SetError(UsernameProperty, x.ErrorMessage)); + } + } + + private const string PasswordProperty = "Password"; + public string Password + { + get { return _data.Password; } + set + { + if (_data.Password != value) { _data.Password = value; RaisePropertyChanged(PasswordProperty); } + ClearError(PasswordProperty); + var validationResult = _validator.Validate(this, PasswordProperty); + if (!validationResult.IsValid) + validationResult.Errors.ToList().ForEach(x => SetError(PasswordProperty, x.ErrorMessage)); + } + } + + private const string EmailProperty = "Email"; + private string _email; + public string Email + { + get { return _data.Email; } + set + { + if (_data.Email != value) { _data.Email = value; RaisePropertyChanged(EmailProperty); } + ClearError(EmailProperty); + var validationResult = _validator.Validate(this, EmailProperty); + if (!validationResult.IsValid) + validationResult.Errors.ToList().ForEach(x => SetError(EmailProperty, x.ErrorMessage)); + } + } + + private const string DateOfBirthProperty = "DateOfBirth"; + public DateTime DateOfBirth + { + get { return _data.DateOfBirth; } + set + { + if (_data.DateOfBirth != value) { _data.DateOfBirth = value; RaisePropertyChanged(DateOfBirthProperty); } + ClearError(DateOfBirthProperty); + var validationResult = _validator.Validate(this, DateOfBirthProperty); + if (!validationResult.IsValid) + validationResult.Errors.ToList().ForEach(x => SetError(DateOfBirthProperty, x.ErrorMessage)); + } + } + + private const string DescriptionProperty = "Description"; + public string Description + { + get { return _data.Description; } + set + { + if (_data.Description != value) { _data.Description = value; RaisePropertyChanged(DescriptionProperty); } + ClearError(DescriptionProperty); + var validationResult = _validator.Validate(this, DescriptionProperty); + if (!validationResult.IsValid) + validationResult.Errors.ToList().ForEach(x => SetError(DescriptionProperty, x.ErrorMessage)); + } + } + + #endregion + + #region Commands + + public ICommand OkCommand { get; set; } + public ICommand CancelCommand { get; set; } + + private void OkCommandExecute(object obj) + { + MessageBox.Show("Saved to imaginary database :)"); + } + + private bool OkCommandCanExecute(object obj) + { + return !string.IsNullOrEmpty(Username); + } + + private void CancelCommandExecute(object obj) + { + + } + + private bool CancelCommandCanExecute(object obj) + { + return !string.IsNullOrEmpty(Username); + } + + #endregion + + #region Implementation of IEditableObject + + public void BeginEdit() + { + if (_isDirty) return; + _backup = _data; + _isDirty = true; + } + + public void EndEdit() + { + if (_isDirty) + { + ResetModels(); + _isDirty = false; + } + } + + public void CancelEdit() + { + if (!_isDirty) return; + _data = _backup; + _isDirty = false; + } + + #endregion + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightValidation/ViewModelBase.cs Wed Apr 18 22:28:46 2012 +0100 @@ -0,0 +1,74 @@ +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; + +namespace SilverlightValidation +{ + public class ViewModelBase : INotifyPropertyChanged, IDataErrorInfo + { + #region INotifyPropertyChanged method plus event + + public event PropertyChangedEventHandler PropertyChanged = delegate { }; + + protected void RaisePropertyChanged(string propertyName) + { + PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); + } + + #endregion + + #region IDataErrorInfo methods and helpers + + private readonly Dictionary<string, string> _errors = new Dictionary<string, string>(); + + public virtual bool HasErrors + { + get { return _errors.Count > 0; } + } + + public void SetError(string propertyName, string errorMessage) + { + _errors[propertyName] = errorMessage; + RaisePropertyChanged(propertyName); + } + + protected void ClearError(string propertyName) + { + _errors.Remove(propertyName); + RaisePropertyChanged(propertyName); + } + + protected void ClearAllErrors() + { + var properties = _errors.Select(error => error.Key).ToList(); + + _errors.Clear(); + + foreach (string property in properties) + RaisePropertyChanged(property); + } + + public string Error + { + get + { + var sb = new StringBuilder(); + + foreach (var item in _errors) + { + sb.AppendLine(item.Value); + } + + return sb.ToString(); + } + } + + public string this[string columnName] + { + get { return _errors.ContainsKey(columnName) ? _errors[columnName] : string.Empty; } + } + + #endregion + } +}