Mercurial > silverbladetech
changeset 58:241e2f22ed3c
Latest version
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightGlimpse/Controls/BrokenBindingsViewer.xaml Sat Apr 21 15:06:48 2012 +0100 @@ -0,0 +1,9 @@ +<UserControl x:Class="SilverlightGlimpse.Controls.BrokenBindingsViewer" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> + <Grid x:Name="LayoutRoot" Background="White"> + <ScrollViewer> + <ItemsControl x:Name="icBrokenBindings" /> + </ScrollViewer> + </Grid> +</UserControl>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightGlimpse/Controls/BrokenBindingsViewer.xaml.cs Sat Apr 21 15:06:48 2012 +0100 @@ -0,0 +1,91 @@ +using System.Reflection; +using System.Windows.Data; +using SilverlightGlimpse.Models; +using System.Windows; +using System.Diagnostics; +using System.Windows.Media; + +namespace SilverlightGlimpse.Controls +{ + public partial class BrokenBindingsViewer + { + public BrokenBindingsViewer() + { + InitializeComponent(); + } + + private void BrokenBindings_Loaded(object sender, RoutedEventArgs e) + { + this.icBrokenBindings.Items.Clear(); + LoadBrokenBindings(GlimpseService.CreateInstance.RootVisual); + } + + private void LoadBrokenBindings(UIElement uiElement) + { + var frameworkElement = uiElement as FrameworkElement; + + if (frameworkElement != null) + { + foreach (var fieldInfo in frameworkElement.GetType().GetFields(BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Static)) + { + if (object.ReferenceEquals(fieldInfo.FieldType, typeof(DependencyProperty))) + { + var bindingExpression = frameworkElement.GetBindingExpression((DependencyProperty)fieldInfo.GetValue(null)); + + if (bindingExpression != null && bindingExpression.ParentBinding.Source == null && bindingExpression.ParentBinding.RelativeSource == null) + { + var isInherited = false; + + if (frameworkElement.DataContext != null && !string.IsNullOrEmpty(bindingExpression.ParentBinding.Path.Path)) + { + foreach (var propertyInfo in frameworkElement.DataContext.GetType().GetProperties(BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Instance)) + { + if (string.Compare(propertyInfo.Name, bindingExpression.ParentBinding.Path.Path) == 0) + { + isInherited = true; + break; // TODO: might not be correct. Was : Exit For + } + } + } + + if (isInherited) + { + break; // TODO: might not be correct. Was : Exit For + } + + //this code handles empty bindings on the Button controls + //I'll have to look into why the Button has an empty or unresolved binding + if (string.IsNullOrEmpty(frameworkElement.Name) + && frameworkElement.GetType().Name == "TextBlock" + && fieldInfo.Name == "TextProperty" + && string.IsNullOrEmpty(bindingExpression.ParentBinding.Path.Path)) + { + break; // TODO: might not be correct. Was : Exit For + } + + BrokenBinding objBrokenBinding = new BrokenBinding( + frameworkElement.Name, + frameworkElement.GetType().Name, + fieldInfo.Name, + bindingExpression.ParentBinding.Path.Path); + this.icBrokenBindings.Items.Add(objBrokenBinding); + Debug.WriteLine("Broken Binding - ", objBrokenBinding.ToString()); + } + } + } + + int children = VisualTreeHelper.GetChildrenCount(frameworkElement); + + for (int j = 0; j <= children - 1; j++) + { + FrameworkElement child = VisualTreeHelper.GetChild(frameworkElement, j) as FrameworkElement; + + if (child != null) + { + LoadBrokenBindings(child); + } + } + } + } + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightGlimpse/Controls/ExceptionsViewer.xaml Sat Apr 21 15:06:48 2012 +0100 @@ -0,0 +1,105 @@ +<UserControl x:Class="SilverlightGlimpse.Controls.ExceptionsViewer" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> + <Grid x:Name="LayoutRoot" Background="White"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="250" /> + <ColumnDefinition Width="*" /> + </Grid.ColumnDefinitions> + <Grid.RowDefinitions> + <RowDefinition Height="Auto" /> + <RowDefinition Height="*" /> + <RowDefinition Height="Auto" /> + </Grid.RowDefinitions> + + <TextBlock Grid.ColumnSpan="2" + Margin="3.5" + VerticalAlignment="Center" + FontSize="18" + Foreground="Red" + Text="Exceptions Viewer" /> + + <ListBox x:Name="lbExceptions" + Grid.Row="1" + Margin="3.5" + ItemsSource="{Binding}" + SelectionChanged="lbExceptions_SelectionChanged" /> + + <ScrollViewer Grid.Row="1" + Grid.Column="1" + Margin="3.5" + DataContext="{Binding ElementName=lbExceptions, + Path=SelectedItem}"> + <Grid> + <Grid.RowDefinitions> + <RowDefinition Height="Auto" /> + <RowDefinition Height="Auto" /> + <RowDefinition Height="Auto" /> + <RowDefinition Height="Auto" /> + <RowDefinition Height="Auto" /> + <RowDefinition Height="Auto" /> + <RowDefinition Height="Auto" /> + <RowDefinition Height="Auto" /> + </Grid.RowDefinitions> + + <Rectangle Fill="BlanchedAlmond" /> + <TextBlock x:Name="tbAction" + FontSize="14" + Text="Action" + TextDecorations="Underline" /> + <TextBlock Grid.Row="1" + FontSize="11" + Text="{Binding Path=Action}" + TextWrapping="Wrap" + Visibility="{Binding ElementName=tbAction, + Path=Visibility}" /> + + <Rectangle Grid.Row="2" Fill="BlanchedAlmond" /> + <TextBlock Grid.Row="2" + Margin="0,7,0,0" + FontSize="14" + Text="Control Name" + TextDecorations="Underline" + Visibility="{Binding ElementName=tbAction, + Path=Visibility}" /> + <TextBlock Grid.Row="3" + FontSize="11" + Text="{Binding Path=ControlName}" + TextWrapping="Wrap" + Visibility="{Binding ElementName=tbAction, + Path=Visibility}" /> + + <Rectangle Grid.Row="4" Fill="BlanchedAlmond" /> + <TextBlock Grid.Row="4" + Margin="0,7,0,0" + FontSize="14" + Text="Message" + TextDecorations="Underline" /> + <TextBlock Grid.Row="5" + FontSize="11" + Text="{Binding Path=Exception.Message}" + TextWrapping="Wrap" /> + + <Rectangle Grid.Row="6" Fill="BlanchedAlmond" /> + <TextBlock Grid.Row="6" + Margin="0,7,0,0" + FontSize="14" + Text="Stack Trace" + TextDecorations="Underline" /> + <TextBlock Grid.Row="7" + FontSize="11" + Text="{Binding Path=Exception.StackTrace}" + TextWrapping="Wrap" /> + + </Grid> + </ScrollViewer> + <Button Grid.Row="2" + Grid.Column="1" + Margin="11" + HorizontalAlignment="Right" + VerticalAlignment="Center" + Click="ClearExceptions_Click" + Content="Clear Exceptions" + Padding="7" /> + </Grid> +</UserControl>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightGlimpse/Controls/ExceptionsViewer.xaml.cs Sat Apr 21 15:06:48 2012 +0100 @@ -0,0 +1,38 @@ +using System; +using System.Windows; +using SilverlightGlimpse.Models; +using System.Windows.Controls; + +namespace SilverlightGlimpse.Controls +{ + public partial class ExceptionsViewer + { + public ExceptionsViewer() + { + InitializeComponent(); + } + + private void ClearExceptions_Click(object sender, RoutedEventArgs e) + { + GlimpseService.CreateInstance.HostExceptions.Clear(); + } + + private void ExceptionsViewer_Loaded(object sender, RoutedEventArgs e) + { + this.DataContext = GlimpseService.CreateInstance.HostExceptions; + if (GlimpseService.CreateInstance.HostExceptions.Count > 0) + this.lbExceptions.SelectedIndex = 0; + } + + private void lbExceptions_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (this.lbExceptions.SelectedItem != null && this.lbExceptions.SelectedItem is ExceptionWrapper) + { + if (((ExceptionWrapper)this.lbExceptions.SelectedItem).IsValidationException) + this.tbAction.Visibility = Visibility.Visible; + else + this.tbAction.Visibility = Visibility.Collapsed; + } + } + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightGlimpse/Controls/GlimpseViewer.xaml Sat Apr 21 15:06:48 2012 +0100 @@ -0,0 +1,79 @@ +<UserControl x:Class="SilverlightGlimpse.Controls.GlimpseViewer" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:c="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls" + xmlns:localc="clr-namespace:SilverlightGlimpse.Controls"> + <Grid x:Name="LayoutRoot" Background="Khaki"> + <Grid.Resources> + <SolidColorBrush x:Name="noExceptionsBrush" Color="LightGreen" /> + <SolidColorBrush x:Name="hasExceptionsBrush" Color="Red" /> + </Grid.Resources> + <Grid x:Name="layoutInstrumentPanel"> + <StackPanel Orientation="Horizontal"> + <Grid Margin="7"> + <Ellipse x:Name="elpValidationExceptions" + Width="40" + Height="40" + Fill="LightGreen" + Stroke="Brown" + StrokeThickness="2" /> + <TextBlock x:Name="tbValidationExceptions" + HorizontalAlignment="Center" + VerticalAlignment="Center" + FontSize="12" + FontWeight="Bold" + Text="0" + ToolTipService.ToolTip="Binding Exception Count" /> + </Grid> + <Grid Margin="7"> + <Ellipse x:Name="elpUnhandledExceptions" + Width="40" + Height="40" + Fill="LightGreen" + Stroke="Brown" + StrokeThickness="2" /> + <TextBlock x:Name="tbUnhandledExceptions" + HorizontalAlignment="Center" + VerticalAlignment="Center" + FontSize="12" + FontWeight="Bold" + Text="0" + ToolTipService.ToolTip="Unhandled Exception Count" /> + </Grid> + <Button x:Name="btnExpand" + Margin="7" + VerticalAlignment="Center" + Content="Expand" /> + </StackPanel> + </Grid> + <Grid x:Name="layoutViewer" Visibility="Collapsed"> + <Grid.RowDefinitions> + <RowDefinition Height="Auto" /> + <RowDefinition Height="*" /> + </Grid.RowDefinitions> + <TextBlock Margin="3.5" + VerticalAlignment="Center" + FontSize="18" + Foreground="DarkGreen" + Text="Glimpse Viewer" /> + <Button x:Name="btnContract" + Margin="7" + HorizontalAlignment="Right" + VerticalAlignment="Center" + Content="Contract" /> + <c:TabControl Grid.Row="1" + Width="690" + Height="390" + Background="Khaki" + SelectedIndex="2"> + <c:TabItem Header="Exceptions"> + <localc:ExceptionsViewer /> + </c:TabItem> + <c:TabItem Header="Bindings with no Source"> + <localc:BrokenBindingsViewer /> + </c:TabItem> + </c:TabControl> + </Grid> + </Grid> + +</UserControl>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightGlimpse/Controls/GlimpseViewer.xaml.cs Sat Apr 21 15:06:48 2012 +0100 @@ -0,0 +1,52 @@ +using System.Collections.Specialized; +using System.Windows; +using SilverlightGlimpse.Models; + +namespace SilverlightGlimpse.Controls +{ + public partial class GlimpseViewer + { + public GlimpseViewer() + { + InitializeComponent(); + this.DataContext = GlimpseService.CreateInstance; + GlimpseService.CreateInstance.HostExceptions.CollectionChanged += HostExceptions_CollectionChanged; + } + + private void btnContract_Click(object sender, System.Windows.RoutedEventArgs e) + { + this.layoutViewer.Visibility = Visibility.Collapsed; + } + + private void btnExpand_Click(object sender, System.Windows.RoutedEventArgs e) + { + this.layoutViewer.Visibility = Visibility.Visible; + } + + private void HostExceptions_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + int unhandledExceptionCount = 0; + int validationExceptionCount = 0; + + foreach (ExceptionWrapper ew in GlimpseService.CreateInstance.HostExceptions) + { + if (ew.IsValidationException) + validationExceptionCount++; + else + unhandledExceptionCount++; + } + + this.tbValidationExceptions.Text = validationExceptionCount.ToString(); + + this.elpValidationExceptions.Fill = validationExceptionCount == 0 + ? this.noExceptionsBrush + : this.hasExceptionsBrush; + + this.tbUnhandledExceptions.Text = unhandledExceptionCount.ToString(); + + this.elpUnhandledExceptions.Fill = unhandledExceptionCount == 0 + ? this.noExceptionsBrush + : this.hasExceptionsBrush; + } + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightGlimpse/Controls/LoadExceptionViewer.xaml Sat Apr 21 15:06:48 2012 +0100 @@ -0,0 +1,79 @@ +<UserControl x:Class="SilverlightGlimpse.Controls.LoadExceptionViewer" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> + <Border Width="700" + Height="375" + Margin="11" + Background="LightYellow" + BorderBrush="Red" + BorderThickness="2" + CornerRadius="20" + Padding="11"> + <Grid x:Name="LayoutRoot"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="200" /> + <ColumnDefinition Width="*" /> + </Grid.ColumnDefinitions> + <Grid.RowDefinitions> + <RowDefinition Height="Auto" /> + <RowDefinition Height="*" /> + </Grid.RowDefinitions> + <TextBlock Grid.ColumnSpan="2" + Margin="3.5" + VerticalAlignment="Center" + FontSize="18" + Foreground="Red" + Text="Exception Viewer" /> + + <ListBox x:Name="lbExceptions" + Grid.Row="1" + Margin="3.5" + DisplayMemberPath="Message" /> + + <TextBlock x:Name="txtSourceLocation" + Grid.ColumnSpan="2" + HorizontalAlignment="Right" + VerticalAlignment="Center" + FontSize="14" /> + <ScrollViewer Grid.Row="1" + Grid.Column="1" + Margin="3.5" + Background="White" + DataContext="{Binding ElementName=lbExceptions, + Path=SelectedItem}"> + <Grid> + <Grid.RowDefinitions> + <RowDefinition Height="Auto" /> + <RowDefinition Height="Auto" /> + <RowDefinition Height="Auto" /> + <RowDefinition Height="Auto" /> + <RowDefinition Height="Auto" /> + <RowDefinition Height="Auto" /> + </Grid.RowDefinitions> + <Rectangle Fill="BlanchedAlmond" /> + <TextBlock FontSize="14" + Text="Message" + TextDecorations="Underline" /> + <TextBlock Grid.Row="1" + FontSize="11" + Text="{Binding Path=Message}" + TextWrapping="Wrap" /> + + <Rectangle Grid.Row="2" Fill="BlanchedAlmond" /> + <TextBlock Grid.Row="2" + Margin="0,11,0,0" + FontSize="14" + Text="Stack Trace" + TextDecorations="Underline" /> + <TextBlock Grid.Row="3" + FontSize="11" + Text="{Binding Path=StackTrace}" + TextWrapping="Wrap" /> + + </Grid> + </ScrollViewer> + </Grid> + </Border> + +</UserControl> +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightGlimpse/Controls/LoadExceptionViewer.xaml.cs Sat Apr 21 15:06:48 2012 +0100 @@ -0,0 +1,31 @@ +using System; + +namespace SilverlightGlimpse.Controls +{ + public partial class LoadExceptionViewer + { + public LoadExceptionViewer() + { + InitializeComponent(); + } + + public LoadExceptionViewer(Exception e, string sourceLocation) + : this() + { + this.txtSourceLocation.Text = string.Concat("Source Location: ", sourceLocation); + + Exception ex = e; + + while (ex != null) + { + this.lbExceptions.Items.Add(ex); + ex = ex.InnerException; + } + + if (this.lbExceptions.Items.Count > 0) + { + this.lbExceptions.SelectedIndex = 0; + } + } + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightGlimpse/Models/BrokenBinding.cs Sat Apr 21 15:06:48 2012 +0100 @@ -0,0 +1,50 @@ + +namespace SilverlightGlimpse.Models +{ + public class BrokenBinding + { + #region Fields + + private string _controlName = string.Empty; + private string _controlTypeName = string.Empty; + private string _path = string.Empty; + private string _propertyName = string.Empty; + + #endregion + + #region Constructor + + public BrokenBinding(string controlName, string controlTypeName, string propertyName, string path) + { + _controlName = controlName; + _controlTypeName = controlTypeName; + _propertyName = propertyName; + _path = path; + } + + #endregion + + #region Properties + + public string ControlName { get { return string.IsNullOrEmpty(_controlName) ? "(none)" : _controlName; } } + public string ControlTypeName { get { return _controlTypeName; } } + public string Path { get { return _path; } } + public string PropertyName { get { return _propertyName; } } + + #endregion + + #region Methods + + public override string ToString() + { + return string.Format( + "Control Name: {0}, Type: {1}, Property: {2}, Path: {3}", + this.ControlName, + this.ControlTypeName, + this.PropertyName, + this.Path); + } + + #endregion + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightGlimpse/Models/ExceptionWrapper.cs Sat Apr 21 15:06:48 2012 +0100 @@ -0,0 +1,54 @@ +using System; +using System.Windows.Controls; + +namespace SilverlightGlimpse.Models +{ + public class ExceptionWrapper + { + #region Fields + + private bool _isValidationException = false; + private ValidationErrorEventAction _enumAction = ValidationErrorEventAction.Added; + private Exception _exception; + private string _controlName = string.Empty; + + #endregion + + #region Constructor + + public ExceptionWrapper(Exception e) + { + _exception = e; + } + + #endregion + + #region Properties + + public ExceptionWrapper(ValidationErrorEventAction enumAction, string controlName, Exception validationException) + { + _enumAction = enumAction; + _controlName = controlName; + _exception = validationException; + _isValidationException = true; + } + + public ValidationErrorEventAction Action { get { return _enumAction; } } + public string ControlName { get { return _controlName; } } + public Exception Exception { get { return _exception; } } + public bool IsValidationException { get { return _isValidationException; } } + + #endregion + + #region Methods + + public override string ToString() + { + return _isValidationException + ? string.Format("({0}) - {1}", this.Action, Exception.Message) + : Exception.Message; + } + + #endregion + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightGlimpse/Properties/AppManifest.xml Sat Apr 21 15:06:48 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/SilverlightGlimpse/Properties/AssemblyInfo.cs Sat Apr 21 15:06:48 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("SilverlightGlimpse")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SilverlightGlimpse")] +[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("52ef33ca-e923-41ef-a7c8-98ec475bc956")] + +// 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/SilverlightGlimpse/Services/GlimpseService.cs Sat Apr 21 15:06:48 2012 +0100 @@ -0,0 +1,110 @@ +using System; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Windows; +using System.Windows.Controls; +using SilverlightGlimpse.Controls; + +namespace SilverlightGlimpse.Models +{ + public class GlimpseService + { + #region Fields + + private static GlimpseService _instance; + + #endregion + + #region Private constructor + + private GlimpseService() + { + RootVisual.BindingValidationError += HostRootVisual_BindingValidationError; + App.UnhandledException += Application_UnhandledException; + } + + #endregion + + #region Properties + + public static GlimpseService CreateInstance + { + get { return (_instance == null) ? _instance = new GlimpseService() : _instance; } + } + + internal Application App { get; private set; } + internal ChildWindow GlimpseWindow { get; set;} + internal string HostApplicationName { get; set; } + internal ObservableCollection<ExceptionWrapper> HostExceptions { get; private set; } + internal FrameworkElement RootVisual { get; private set; } + + #endregion + + #region Creation and Loading + + public void DisplayLoadFailure(Application app, Exception ex, string hostApplicationName) + { + Debug.WriteLine("{0} had exception. {1}", this.HostApplicationName, ex.ToString()); + App = app; + RootVisual = new LoadExceptionViewer(ex, hostApplicationName); + + //RootVisual.BindingValidationError += HostRootVisual_BindingValidationError; + //App.UnhandledException += Application_UnhandledException; + } + + public void Load(Application app, string hostApplicationName) + { + this.App = app; + this.RootVisual = App.RootVisual as FrameworkElement; + this.HostApplicationName = hostApplicationName; + + //RootVisual.BindingValidationError += HostRootVisual_BindingValidationError; + //App.UnhandledException += Application_UnhandledException; + + ChildWindow window = new ChildWindow(); + window.Title = this.HostApplicationName; + window.Content = new GlimpseViewer(); + window.Show(); + } + + #endregion + + #region Events handlers + + private void HostRootVisual_BindingValidationError(object sender, ValidationErrorEventArgs e) + { + string controlName = "(none)"; + Control control = e.OriginalSource as Control; + + if (control != null && !string.IsNullOrEmpty(control.Name)) + { + controlName = control.Name; + } + + Exception ex = e.Error.Exception; + + while (ex != null) + { + this.HostExceptions.Add(new ExceptionWrapper(e.Action, controlName, e.Error.Exception)); + ex = ex.InnerException; + } + } + + private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e) + { + Debug.WriteLine("{0} had exception. {1}", this.HostApplicationName, e.ExceptionObject.ToString()); + + Exception ex = e.ExceptionObject; + + while (ex != null) + { + this.HostExceptions.Add(new ExceptionWrapper(ex)); + ex = ex.InnerException; + } + + e.Handled = true; + } + + #endregion + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightGlimpse/SilverlightGlimpse.csproj Sat Apr 21 15:06:48 2012 +0100 @@ -0,0 +1,127 @@ +<?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>{BB51026B-2864-4389-AACA-0BBDF1926E46}</ProjectGuid> + <ProjectTypeGuids>{A1591282-1198-4647-A2B1-27E5FF5F6F3B};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids> + <OutputType>Library</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>SilverlightGlimpse</RootNamespace> + <AssemblyName>SilverlightGlimpse</AssemblyName> + <TargetFrameworkIdentifier>Silverlight</TargetFrameworkIdentifier> + <TargetFrameworkVersion>v5.0</TargetFrameworkVersion> + <SilverlightVersion>$(TargetFrameworkVersion)</SilverlightVersion> + <SilverlightApplication>true</SilverlightApplication> + <SupportedCultures> + </SupportedCultures> + <XapOutputs>true</XapOutputs> + <GenerateSilverlightManifest>true</GenerateSilverlightManifest> + <XapFilename>SilverlightGlimpse.xap</XapFilename> + <SilverlightManifestTemplate>Properties\AppManifest.xml</SilverlightManifestTemplate> + <SilverlightAppEntry>SilverlightGlimpse.App</SilverlightAppEntry> + <TestPageFileName>SilverlightGlimpseTestPage.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="mscorlib" /> + <Reference Include="System.Windows" /> + <Reference Include="system" /> + <Reference Include="System.Core" /> + <Reference Include="System.Net" /> + <Reference Include="System.Windows.Controls, Version=5.0.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" /> + <Reference Include="System.Xml" /> + <Reference Include="System.Windows.Browser" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Controls\BrokenBindingsViewer.xaml.cs"> + <DependentUpon>BrokenBindingsViewer.xaml</DependentUpon> + </Compile> + <Compile Include="Controls\GlimpseViewer.xaml.cs"> + <DependentUpon>GlimpseViewer.xaml</DependentUpon> + </Compile> + <Compile Include="Controls\LoadExceptionViewer.xaml.cs"> + <DependentUpon>LoadExceptionViewer.xaml</DependentUpon> + </Compile> + <Compile Include="Controls\ExceptionsViewer.xaml.cs"> + <DependentUpon>ExceptionsViewer.xaml</DependentUpon> + </Compile> + <Compile Include="Models\BrokenBinding.cs" /> + <Compile Include="Models\ExceptionWrapper.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + <Compile Include="Services\GlimpseService.cs" /> + </ItemGroup> + <ItemGroup> + <Page Include="Controls\BrokenBindingsViewer.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + <Page Include="Controls\GlimpseViewer.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + <Page Include="Controls\LoadExceptionViewer.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + <Page Include="Controls\ExceptionsViewer.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
Binary file SilverlightValidation/SilverlightValidation.Web/ClientBin/SilverlightValidation.xap has changed
--- a/SilverlightValidation/SilverlightValidation.sln Thu Apr 19 14:39:59 2012 +0100 +++ b/SilverlightValidation/SilverlightValidation.sln Sat Apr 21 15:06:48 2012 +0100 @@ -5,6 +5,8 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SilverlightValidation.Web", "SilverlightValidation.Web\SilverlightValidation.Web.csproj", "{E65C6757-932B-4D01-9A8A-6D02F8FAA25A}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SilverlightGlimpse", "SilverlightGlimpse\SilverlightGlimpse.csproj", "{BB51026B-2864-4389-AACA-0BBDF1926E46}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -19,6 +21,10 @@ {E65C6757-932B-4D01-9A8A-6D02F8FAA25A}.Debug|Any CPU.Build.0 = Debug|Any CPU {E65C6757-932B-4D01-9A8A-6D02F8FAA25A}.Release|Any CPU.ActiveCfg = Release|Any CPU {E65C6757-932B-4D01-9A8A-6D02F8FAA25A}.Release|Any CPU.Build.0 = Release|Any CPU + {BB51026B-2864-4389-AACA-0BBDF1926E46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BB51026B-2864-4389-AACA-0BBDF1926E46}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BB51026B-2864-4389-AACA-0BBDF1926E46}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BB51026B-2864-4389-AACA-0BBDF1926E46}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE
--- a/SilverlightValidation/SilverlightValidation/App.xaml.cs Thu Apr 19 14:39:59 2012 +0100 +++ b/SilverlightValidation/SilverlightValidation/App.xaml.cs Sat Apr 21 15:06:48 2012 +0100 @@ -1,59 +1,71 @@ using System; using System.Windows; +using System.Windows.Controls; +using System.Windows.Navigation; +using Glimpse; namespace SilverlightValidation { - public partial class App : Application + 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) + { + try + { + this.RootVisual = new Views.UserListView(); + + GlimpseService.CreateInstance.Load(this, "Glimpse Demo"); + } + catch (Exception ex) + { + GlimpseService.CreateInstance.DisplayLoadFailure(this, ex, "Glimpse Demo"); + } + } + + private void Application_Exit(object sender, EventArgs e) { - 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) + { - 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); }); + } + } - // 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"); - 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) - { - } - } + 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/Commands/RelayCommand.cs Sat Apr 21 15:06:48 2012 +0100 @@ -0,0 +1,40 @@ +using System; +using System.Windows.Input; + +namespace SilverlightValidation.Commands +{ + public class RelayCommand : ICommand + { + public event EventHandler CanExecuteChanged = delegate { }; + + 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() + { + 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/Data/Factory.cs Sat Apr 21 15:06:48 2012 +0100 @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using SilverlightValidation.Models; + +namespace SilverlightValidation.Data +{ + public class Factory + { + public static IList<UserModel> CreateUserModels() + { + return new List<UserModel>(5) + { + new UserModel() { Username = "StevenH", Password = "Password1*", Email = "steven@hotmail.com", DateOfBirth = new DateTime(1977, 09, 01), Description = ""}, + new UserModel() { Username = "RichardJ", Password = "&12N456a", Email = "dicky@gmail.com", DateOfBirth = new DateTime(1983, 03, 13), Description = "Rebel"}, + new UserModel() { Username = "BobbyP", Password = "p@a33Word", Email = "bob@yahoo.co.uk", DateOfBirth = new DateTime(1992, 08, 30), Description = ""}, + new UserModel() { Username = "DavidM", Password = "][poIu789*", Email = "daveyboy@marsh.com", DateOfBirth = new DateTime(1965, 06, 21), Description = "Renegade"}, + new UserModel() { Username = "JessieJ", Password = "';lkJh567", Email = "jj@apple.co.uk", DateOfBirth = new DateTime(1990, 10, 15), Description = ""} + }; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightValidation/Diagrams/Form.cd Sat Apr 21 15:06:48 2012 +0100 @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="utf-8"?> +<ClassDiagram MajorVersion="1" MinorVersion="1"> + <Class Name="SilverlightValidation.RelayCommand" Collapsed="true" BaseTypeListCollapsed="true"> + <Position X="6.75" Y="5.5" Width="2" /> + <TypeIdentifier> + <HashCode>AAAAAAAAIEACAAQAAECAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode> + <FileName>RelayCommand.cs</FileName> + </TypeIdentifier> + <Lollipop Position="0.2" Collapsed="true" /> + </Class> + <Class Name="SilverlightValidation.ViewModelBase"> + <Position X="1.75" Y="0.5" Width="2" /> + <TypeIdentifier> + <HashCode>AAAAAAACAABQAAABAAAAAgAAgAAAAACIAAAAAAARAAA=</HashCode> + <FileName>ViewModelBase.cs</FileName> + </TypeIdentifier> + <Lollipop Position="0.2" /> + </Class> + <Class Name="SilverlightValidation.UserModel" BaseTypeListCollapsed="true"> + <Position X="9.25" Y="0.5" Width="1.5" /> + <TypeIdentifier> + <HashCode>AAAAAAAAACAgAAAAAQAAAAAAAAAQAEACAAAAAAAAABA=</HashCode> + <FileName>UserModel.cs</FileName> + </TypeIdentifier> + <Lollipop Position="0.2" Collapsed="true" /> + </Class> + <Class Name="SilverlightValidation.UserModelValidator"> + <Position X="6.75" Y="3.75" Width="2" /> + <TypeIdentifier> + <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAA=</HashCode> + <FileName>UserModelValidator.cs</FileName> + </TypeIdentifier> + </Class> + <Class Name="SilverlightValidation.UserViewModel"> + <Position X="4.25" Y="0.5" Width="2" /> + <TypeIdentifier> + <HashCode>UAAAoIIABCIgAAAAEYAAGAAAAAAQABAKQAAAAAAAIAA=</HashCode> + <FileName>UserViewModel.cs</FileName> + </TypeIdentifier> + <Lollipop Position="0.2" /> + </Class> + <Interface Name="SilverlightValidation.IUserModel"> + <Position X="6.75" Y="0.5" Width="2" /> + <TypeIdentifier> + <HashCode>AAAAAAAAACAgAAAAAQAAAAAAAAAQAAACAAAAAAAAAAA=</HashCode> + <FileName>UserModel.cs</FileName> + </TypeIdentifier> + </Interface> + <Interface Name="SilverlightValidation.ICloneable<T>"> + <Position X="6.75" Y="2.5" Width="2" /> + <TypeIdentifier> + <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABA=</HashCode> + <FileName>UserModel.cs</FileName> + </TypeIdentifier> + </Interface> + <Font Name="Segoe UI" Size="9" /> +</ClassDiagram> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightValidation/Diagrams/List.cd Sat Apr 21 15:06:48 2012 +0100 @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="utf-8"?> +<ClassDiagram MajorVersion="1" MinorVersion="1"> + <Class Name="SilverlightValidation.UserListViewModel"> + <Position X="8.25" Y="0.75" Width="2" /> + <TypeIdentifier> + <HashCode>QAAAIAIAAAIAAAAAAAAAEAAAAAAAABAIQAAAAAAAAAA=</HashCode> + <FileName>UserListViewModel.cs</FileName> + </TypeIdentifier> + <Lollipop Position="0.2" /> + </Class> + <Class Name="SilverlightValidation.ViewModelBase"> + <Position X="5.5" Y="0.75" Width="2.25" /> + <TypeIdentifier> + <HashCode>AAAAAAACAABQAAABAAAAAgAAgAAAAACIAAAAAAARAAA=</HashCode> + <FileName>ViewModelBase.cs</FileName> + </TypeIdentifier> + <Lollipop Position="0.2" /> + </Class> + <Class Name="SilverlightValidation.UserViewModel"> + <Position X="3" Y="0.75" Width="2" /> + <TypeIdentifier> + <HashCode>UAAAoIIADCIgAAAAEYAAGAAAAAAQABAKQEAAAAAgIAA=</HashCode> + <FileName>UserViewModel.cs</FileName> + </TypeIdentifier> + <Lollipop Position="0.2" /> + </Class> + <Class Name="SilverlightValidation.UserModel" BaseTypeListCollapsed="true"> + <Position X="5.5" Y="4.75" Width="2.25" /> + <TypeIdentifier> + <HashCode>AAAAAAAAACAgAAAAAQAAAAAAAAAQAEACAAAAAAAAABA=</HashCode> + <FileName>UserModel.cs</FileName> + </TypeIdentifier> + <Lollipop Position="0.2" Collapsed="true" /> + </Class> + <Interface Name="SilverlightValidation.IUserModel"> + <Position X="8.25" Y="4.75" Width="1.5" /> + <TypeIdentifier> + <HashCode>AAAAAAAAACAgAAAAAQAAAAAAAAAQAAACAAAAAAAAAAA=</HashCode> + <FileName>UserModel.cs</FileName> + </TypeIdentifier> + </Interface> + <Font Name="Segoe UI" Size="9" /> +</ClassDiagram> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightValidation/Interfaces/ICloneable.cs Sat Apr 21 15:06:48 2012 +0100 @@ -0,0 +1,7 @@ +namespace SilverlightValidation.Interfaces +{ + public interface ICloneable<T> + { + T Clone(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightValidation/Interfaces/IUserModel.cs Sat Apr 21 15:06:48 2012 +0100 @@ -0,0 +1,12 @@ +using System; +namespace SilverlightValidation.Interfaces +{ + public interface IUserModel + { + string Username { get; set; } + string Email { get; set; } + string Password { get; set; } + DateTime? DateOfBirth { get; set; } + string Description { get; set; } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightValidation/Models/UserModel.cs Sat Apr 21 15:06:48 2012 +0100 @@ -0,0 +1,25 @@ +using System; +using System.ComponentModel; +using SilverlightValidation.Interfaces; + +namespace SilverlightValidation.Models +{ + 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 static UserModel Create() + { + return new UserModel() { Username = "", Email = "", Password = "", DateOfBirth = null, Description = "" }; + } + + public UserModel Clone() + { + return (UserModel) this.MemberwiseClone(); + } + } +}
--- a/SilverlightValidation/SilverlightValidation/Overview.cd Thu Apr 19 14:39:59 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<ClassDiagram MajorVersion="1" MinorVersion="1"> - <Class Name="SilverlightValidation.RelayCommand" Collapsed="true" BaseTypeListCollapsed="true"> - <Position X="6.75" Y="5.5" Width="2" /> - <TypeIdentifier> - <HashCode>AAAAAAAAIEACAAQAAECAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode> - <FileName>RelayCommand.cs</FileName> - </TypeIdentifier> - <Lollipop Position="0.2" Collapsed="true" /> - </Class> - <Class Name="SilverlightValidation.ViewModelBase"> - <Position X="1.75" Y="0.5" Width="2" /> - <TypeIdentifier> - <HashCode>AAAAAAACAABQAAABAAAAAgAAgAAAAACIAAAAAAARAAA=</HashCode> - <FileName>ViewModelBase.cs</FileName> - </TypeIdentifier> - <Lollipop Position="0.2" /> - </Class> - <Class Name="SilverlightValidation.UserModel" BaseTypeListCollapsed="true"> - <Position X="9.25" Y="0.5" Width="1.5" /> - <TypeIdentifier> - <HashCode>AAAAAAAAACAgAAAAAQAAAAAAAAAQAEACAAAAAAAAABA=</HashCode> - <FileName>UserModel.cs</FileName> - </TypeIdentifier> - <Lollipop Position="0.2" Collapsed="true" /> - </Class> - <Class Name="SilverlightValidation.UserModelValidator"> - <Position X="6.75" Y="3.75" Width="2" /> - <TypeIdentifier> - <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAA=</HashCode> - <FileName>UserModelValidator.cs</FileName> - </TypeIdentifier> - </Class> - <Class Name="SilverlightValidation.UserViewModel"> - <Position X="4.25" Y="0.5" Width="2" /> - <TypeIdentifier> - <HashCode>UAAAoIIABCIgAAAAEYAAGAAAAAAQABAKQAAAAAAAIAA=</HashCode> - <FileName>UserViewModel.cs</FileName> - </TypeIdentifier> - <Lollipop Position="0.2" /> - </Class> - <Interface Name="SilverlightValidation.IUserModel"> - <Position X="6.75" Y="0.5" Width="2" /> - <TypeIdentifier> - <HashCode>AAAAAAAAACAgAAAAAQAAAAAAAAAQAAACAAAAAAAAAAA=</HashCode> - <FileName>UserModel.cs</FileName> - </TypeIdentifier> - </Interface> - <Interface Name="SilverlightValidation.ICloneable<T>"> - <Position X="6.75" Y="2.5" Width="2" /> - <TypeIdentifier> - <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABA=</HashCode> - <FileName>UserModel.cs</FileName> - </TypeIdentifier> - </Interface> - <Font Name="Segoe UI" Size="9" /> -</ClassDiagram> \ No newline at end of file
--- a/SilverlightValidation/SilverlightValidation/RelayCommand.cs Thu Apr 19 14:39:59 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -using System; -using System.Windows.Input; - -namespace SilverlightValidation -{ - public class RelayCommand : ICommand - { - public event EventHandler CanExecuteChanged = delegate { }; - - 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() - { - CanExecuteChanged(this, new EventArgs()); - } - - - public bool CanExecute(object parameter) - { - return _canExecute == null || _canExecute(parameter); - } - - - public void Execute(object parameter) - { - _execute(parameter); - } - } -}
--- a/SilverlightValidation/SilverlightValidation/SilverlightValidation.csproj Thu Apr 19 14:39:59 2012 +0100 +++ b/SilverlightValidation/SilverlightValidation/SilverlightValidation.csproj Sat Apr 21 15:06:48 2012 +0100 @@ -71,9 +71,15 @@ <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, Version=5.0.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> + <HintPath>..\Libs\System.Windows.Controls.Data.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.Windows.Controls.Navigation, Version=5.0.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> + <HintPath>..\Libs\System.Windows.Controls.Navigation.dll</HintPath> + </Reference> <Reference Include="System.Xml" /> <Reference Include="System.Windows.Browser" /> </ItemGroup> @@ -81,31 +87,51 @@ <Compile Include="App.xaml.cs"> <DependentUpon>App.xaml</DependentUpon> </Compile> + <Compile Include="Data\Factory.cs" /> + <Compile Include="Interfaces\ICloneable.cs" /> + <Compile Include="Interfaces\IUserModel.cs" /> <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"> + <Compile Include="Commands\RelayCommand.cs" /> + <Compile Include="ViewModels\UserListViewModel.cs" /> + <Compile Include="Models\UserModel.cs" /> + <Compile Include="Validators\UserModelValidator.cs" /> + <Compile Include="Views\UserListView.xaml.cs"> + <DependentUpon>UserListView.xaml</DependentUpon> + </Compile> + <Compile Include="Views\UserView.xaml.cs"> <DependentUpon>UserView.xaml</DependentUpon> </Compile> + <Compile Include="ViewModels\UserViewModel.cs" /> + <Compile Include="ViewModels\ViewModelBase.cs" /> </ItemGroup> <ItemGroup> <ApplicationDefinition Include="App.xaml"> <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> </ApplicationDefinition> - <Page Include="UserView.xaml"> + <Page Include="Views\UserListView.xaml"> <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> </Page> + <Page Include="Views\UserView.xaml"> + <Generator>MSBuild:Compile</Generator> + <SubType>Designer</SubType> + </Page> </ItemGroup> <ItemGroup> - <None Include="Overview.cd" /> + <None Include="Diagrams\List.cd" /> + <None Include="Diagrams\Form.cd" /> <None Include="Properties\AppManifest.xml" /> </ItemGroup> - <ItemGroup /> + <ItemGroup> + <Folder Include="Messages\" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\SilverlightGlimpse\SilverlightGlimpse.csproj"> + <Project>{BB51026B-2864-4389-AACA-0BBDF1926E46}</Project> + <Name>SilverlightGlimpse</Name> + </ProjectReference> + </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.
--- a/SilverlightValidation/SilverlightValidation/UserModel.cs Thu Apr 19 14:39:59 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -using System; -using System.ComponentModel; - -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 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 static UserModel Create() - { - return new UserModel() { Username = "", Email = "", Password = "", DateOfBirth = null, Description = "" }; - } - - public UserModel Clone() - { - return (UserModel) this.MemberwiseClone(); - } - } -}
--- a/SilverlightValidation/SilverlightValidation/UserModelValidator.cs Thu Apr 19 14:39:59 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -using System; -using FluentValidation; - -namespace SilverlightValidation -{ - public class UserModelValidator : AbstractValidator<IUserModel> - { - public UserModelValidator() - { - RuleFor(x => x.Username) - .Length(3, 8) - .WithMessage("Must be between 3-8 characters."); - - RuleFor(x => x.Password) - .Matches(@"^\w*(?=\w*\d)(?=\w*[a-z])(?=\w*[A-Z])\w*$") - .WithMessage("Must contain lower, upper and numeric chars."); - - RuleFor(x => x.Email) - .EmailAddress() - .WithMessage("A valid email address is required."); - - RuleFor(x => x.DateOfBirth) - .Must(BeAValidDateOfBirth) - .WithMessage("Must be within 100 years of today."); - } - - private bool BeAValidDateOfBirth(DateTime? dateOfBirth) - { - if (dateOfBirth == null) return false; - if (dateOfBirth.Value > DateTime.Today || dateOfBirth < dateOfBirth.Value.AddYears(-100)) - return false; - return true; - } - } -}
--- a/SilverlightValidation/SilverlightValidation/UserView.xaml Thu Apr 19 14:39:59 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,145 +0,0 @@ -<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:p="clr-namespace:System.Windows.Controls.Primitives;assembly=System.Windows.Controls" - xmlns:s="clr-namespace:System;assembly=mscorlib" - xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" - d:DesignHeight="400" - d:DesignWidth="450" - 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="150" /> - </Grid.RowDefinitions> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="*" /> - <ColumnDefinition Width="100" /> - <ColumnDefinition Width="300" /> - <ColumnDefinition Width="30" /> - <ColumnDefinition Width="*" /> - </Grid.ColumnDefinitions> - - <TextBlock Grid.Row="1" - Grid.Column="1" - Style="{StaticResource LabelStyle}" - Text="Username:" /> - - <TextBox x:Name="tbUsername" - Grid.Row="1" - Grid.Column="2" - LostFocus="tbUsername_LostFocus" - Style="{StaticResource TextBoxStyle}" - Text="{Binding Username, - Mode=TwoWay, - ValidatesOnNotifyDataErrors=True, - NotifyOnValidationError=True}" /> - - <sdk:DescriptionViewer Grid.Row="1" - Grid.Column="3" - Width="20" - Description="Required" - Target="{Binding ElementName=tbUsername}" /> - - <TextBlock Grid.Row="2" - Grid.Column="1" - Style="{StaticResource LabelStyle}" - Text="Password:" /> - - <PasswordBox x:Name="tbPassword" - Grid.Row="2" - Grid.Column="2" - LostFocus="tbPassword_LostFocus" - Password="{Binding Password, - Mode=TwoWay, - ValidatesOnNotifyDataErrors=True, - NotifyOnValidationError=True}" - Style="{StaticResource PasswordBoxStyle}" /> - - <sdk:DescriptionViewer Grid.Row="2" - Grid.Column="3" - Width="20" - Description="Required" - Target="{Binding ElementName=tbPassword}" /> - - <TextBlock Grid.Row="3" - Grid.Column="1" - Style="{StaticResource LabelStyle}" - Text="Email:" /> - - <TextBox x:Name="tbEmail" - Grid.Row="3" - Grid.Column="2" - LostFocus="tbEmail_LostFocus" - Style="{StaticResource TextBoxStyle}" - Text="{Binding Email, - Mode=TwoWay, - ValidatesOnNotifyDataErrors=True, - NotifyOnValidationError=True}" /> - - <sdk:DescriptionViewer Grid.Row="3" - Grid.Column="3" - Width="20" - Description="Required" - Target="{Binding ElementName=tbEmail}" /> - - <TextBlock Grid.Row="4" - Grid.Column="1" - Style="{StaticResource LabelStyle}" - Text="Date of Birth:" /> - - <sdk:DatePicker x:Name="dpDateOfBirth" - Grid.Row="4" - Grid.Column="2" - KeyDown="DatePicker_KeyDown" - LostFocus="dpDateOfBirth_LostFocus" - SelectedDate="{Binding DateOfBirth, - Mode=TwoWay, - ValidatesOnNotifyDataErrors=True, - NotifyOnValidationError=True}" - Style="{StaticResource DatePickerStyle}" /> - <sdk:DescriptionViewer Grid.Row="4" - Grid.Column="3" - Width="20" - Description="Required" - Target="{Binding ElementName=dpDateOfBirth}" /> - - <TextBlock x:Name="tbDescription" - Grid.Row="5" - Grid.Column="1" - Style="{StaticResource LabelStyle}" - Text="Description:" /> - - <TextBox Grid.Row="5" - Grid.Column="2" - Style="{StaticResource TextBoxStyle}" - Text="{Binding Description}" /> - <StackPanel Grid.Row="6" - Grid.Column="2" - HorizontalAlignment="Right" - Orientation="Horizontal"> - <Button Command="{Binding OkCommand}" - Content="OK" - Style="{StaticResource ButtonStyle}" /> - <Button Command="{Binding CancelCommand}" - Content="Cancel" - Style="{StaticResource ButtonStyle}" /> - </StackPanel> - - <sdk:ValidationSummary Grid.Row="7" - Grid.Column="1" - Grid.ColumnSpan="2" - Style="{StaticResource ValidationSummaryStyle}" /> - - </Grid> -</UserControl>
--- a/SilverlightValidation/SilverlightValidation/UserView.xaml.cs Thu Apr 19 14:39:59 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -using System.Windows; -using System.Windows.Browser; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Input; - -namespace SilverlightValidation -{ - public partial class UserView - { - private UserViewModel vm; - public UserView() - { - InitializeComponent(); - HtmlPage.Document.SetProperty("title", "Silverlight Validation"); - - vm = new UserViewModel(UserModel.Create(), new UserModelValidator()); - this.DataContext = vm; - } - - private static void UpdateTextBoxSource(object sender) - { - BindingExpression be = ((TextBox)sender).GetBindingExpression(TextBox.TextProperty); - be.UpdateSource(); - } - - private void DatePicker_KeyDown(object sender, KeyEventArgs e) - { - if (e.Key != Key.Tab) - e.Handled = true; - } - - private void tbUsername_LostFocus(object sender, RoutedEventArgs e) - { - UpdateTextBoxSource(sender); - } - - private void tbPassword_LostFocus(object sender, RoutedEventArgs e) - { - BindingExpression be = ((PasswordBox)sender).GetBindingExpression(PasswordBox.PasswordProperty); - be.UpdateSource(); - } - - private void tbEmail_LostFocus(object sender, RoutedEventArgs e) - { - UpdateTextBoxSource(sender); - } - - private void dpDateOfBirth_LostFocus(object sender, RoutedEventArgs e) - { - BindingExpression be = ((DatePicker)sender).GetBindingExpression(DatePicker.SelectedDateProperty); - be.UpdateSource(); - } - } -} \ No newline at end of file
--- a/SilverlightValidation/SilverlightValidation/UserViewModel.cs Thu Apr 19 14:39:59 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,197 +0,0 @@ -using System; -using System.ComponentModel; -using System.Linq; -using System.Windows; -using System.Windows.Input; -using FluentValidation; - -namespace SilverlightValidation -{ - public class UserViewModel : ViewModelBase, IUserModel, IChangeTracking - { - #region Fields - - private readonly UserModelValidator _validator; - private UserModel _data; - private UserModel _backup; - - #endregion - - #region Constructor - - public UserViewModel(UserModel model, UserModelValidator validator) - { - _validator = validator; - - OkCommand = new RelayCommand(OkCommandExecute); - CancelCommand = new RelayCommand(CancelCommandExecute); - - _data = model; - _backup = model.Clone(); - } - - #endregion - - #region Methods - - private void SetProperties(IUserModel source) - { - Username = source.Username; - Password = source.Password; - Email = source.Email; - DateOfBirth = source.DateOfBirth; - Description = source.Description; - } - - #endregion - - #region Properties - - private const string UsernameProperty = "Username"; - public string Username - { - get { return _data.Username; } - set - { - if (_data.Username != value) - { - _data.Username = value; - RaisePropertyChanged(UsernameProperty); - IsChanged = true; - } - - 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); - IsChanged = true; - } - - 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"; - public string Email - { - get { return _data.Email; } - set - { - if (_data.Email != value) - { - _data.Email = value; - RaisePropertyChanged(EmailProperty); - IsChanged = true; - } - - 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); - IsChanged = true; - } - - 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); - IsChanged = true; - } - - 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) - { - SetProperties(_data); - - if (IsChanged && !HasErrors) - { - AcceptChanges(); - } - } - - private void CancelCommandExecute(object obj) - { - CancelChanges(); - } - - #endregion - - #region IChangeTrack plus Cancel - - public void AcceptChanges() - { - MessageBox.Show("Saving..."); - SetProperties(_backup); - - ClearAllErrors(); - IsChanged = false; - } - - public void CancelChanges() - { - ClearAllErrors(); - if (!IsChanged) return; - SetProperties(_backup); - IsChanged = false; - } - - public bool IsChanged { get; private set; } - - #endregion - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightValidation/Validators/UserModelValidator.cs Sat Apr 21 15:06:48 2012 +0100 @@ -0,0 +1,36 @@ +using System; +using FluentValidation; +using SilverlightValidation.Interfaces; + +namespace SilverlightValidation.Validators +{ + public class UserModelValidator : AbstractValidator<IUserModel> + { + public UserModelValidator() + { + RuleFor(x => x.Username) + .Length(3, 8) + .WithMessage("Must be between 3-8 characters."); + + RuleFor(x => x.Password) + .Matches(@"^\w*(?=\w*\d)(?=\w*[a-z])(?=\w*[A-Z])\w*$") + .WithMessage("Must contain lower, upper and numeric chars."); + + RuleFor(x => x.Email) + .EmailAddress() + .WithMessage("A valid email address is required."); + + RuleFor(x => x.DateOfBirth) + .Must(BeAValidDateOfBirth) + .WithMessage("Must be within 100 years of today."); + } + + private bool BeAValidDateOfBirth(DateTime? dateOfBirth) + { + if (dateOfBirth == null) return false; + if (dateOfBirth.Value > DateTime.Today || dateOfBirth < DateTime.Today.AddYears(-100)) + return false; + return true; + } + } +}
--- a/SilverlightValidation/SilverlightValidation/ViewModelBase.cs Thu Apr 19 14:39:59 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; - -namespace SilverlightValidation -{ - public class ViewModelBase : INotifyPropertyChanged, INotifyDataErrorInfo - { - #region INotifyPropertyChanged method plus event - - public event PropertyChangedEventHandler PropertyChanged = delegate { }; - - protected void RaisePropertyChanged(string propertyName) - { - PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); - } - - #endregion - - #region INotifyDataErrorInfo methods and helpers - - private readonly Dictionary<string, List<string>> _errors = new Dictionary<string, List<string>>(); - - public void SetError(string propertyName, string errorMessage) - { - if (!_errors.ContainsKey(propertyName)) - _errors.Add(propertyName, new List<string> { errorMessage }); - - RaiseErrorsChanged(propertyName); - } - - protected void ClearError(string propertyName) - { - if (_errors.ContainsKey(propertyName)) - _errors.Remove(propertyName); - - RaiseErrorsChanged(propertyName); - } - - protected void ClearAllErrors() - { - var errors = _errors.Select(error => error.Key).ToList(); - - foreach (var propertyName in errors) - ClearError(propertyName); - } - - public void RaiseErrorsChanged(string propertyName) - { - ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName)); - } - - public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged = delegate { }; - - public IEnumerable GetErrors(string propertyName) - { - return _errors.ContainsKey(propertyName) - ? _errors[propertyName] - : null; - } - - public bool HasErrors - { - get { return _errors.Count > 0; } - } - - #endregion - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightValidation/ViewModels/UserListViewModel.cs Sat Apr 21 15:06:48 2012 +0100 @@ -0,0 +1,48 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Windows.Input; +using SilverlightValidation.Commands; +using SilverlightValidation.Models; +using SilverlightValidation.Validators; + +namespace SilverlightValidation.ViewModels +{ + public class UserListViewModel + { + public UserListViewModel(IList<UserModel> models, UserModelValidator validator) + { + Data = new ObservableCollection<UserViewModel>(); + + foreach (var model in models) + Data.Add(new UserViewModel(model, validator)); + + AddCommand = new RelayCommand(AddCommandExecute); + DeleteCommand = new RelayCommand(DeleteCommandExecute); + } + + #region Properties + + public ObservableCollection<UserViewModel> Data { get; set; } + + public UserViewModel SelectedItem { get; set; } + + #endregion + + #region Commands + + public ICommand AddCommand { get; set; } + public ICommand DeleteCommand { get; set; } + + private void AddCommandExecute(object obj) + { + + } + + private void DeleteCommandExecute(object obj) + { + Data.Remove(SelectedItem); + } + + #endregion + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightValidation/ViewModels/UserViewModel.cs Sat Apr 21 15:06:48 2012 +0100 @@ -0,0 +1,227 @@ +using System; +using System.ComponentModel; +using System.Linq; +using System.Windows; +using System.Windows.Input; +using FluentValidation; +using SilverlightValidation.Interfaces; +using SilverlightValidation.Validators; +using SilverlightValidation.Models; +using SilverlightValidation.Commands; + +namespace SilverlightValidation.ViewModels +{ + public class UserViewModel : ViewModelBase, IUserModel, IChangeTracking, IEditableObject + { + #region Fields + + private readonly UserModelValidator _validator; + private UserModel _data; + private UserModel _backup; + + #endregion + + #region Constructor + + public UserViewModel(UserModel model, UserModelValidator validator) + { + _validator = validator; + _data = model; + _backup = model.Clone(); + + OkCommand = new RelayCommand(OkCommandExecute); + CancelCommand = new RelayCommand(CancelCommandExecute); + } + + #endregion + + #region Methods + + private void SetProperties(IUserModel source) + { + Username = source.Username; + Password = source.Password; + Email = source.Email; + DateOfBirth = source.DateOfBirth; + Description = source.Description; + } + + #endregion + + #region Properties + + private const string UsernameProperty = "Username"; + public string Username + { + get { return _data.Username; } + set + { + if (_data.Username != value) + { + _data.Username = value; + RaisePropertyChanged(UsernameProperty); + IsChanged = true; + } + + 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); + IsChanged = true; + } + + 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"; + public string Email + { + get { return _data.Email; } + set + { + if (_data.Email != value) + { + _data.Email = value; + RaisePropertyChanged(EmailProperty); + IsChanged = true; + } + + 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); + IsChanged = true; + } + + 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); + IsChanged = true; + } + + 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) + { + SetProperties(_data); + + if (IsChanged && !HasErrors) + { + AcceptChanges(); + } + } + + private void CancelCommandExecute(object obj) + { + CancelChanges(); + } + + #endregion + + #region IChangeTrack plus Cancel + + public void AcceptChanges() + { + MessageBox.Show("Saving..."); + SetProperties(_backup); + + ClearAllErrors(); + IsChanged = false; + } + + public void CancelChanges() + { + if (!IsChanged) return; + SetProperties(_backup); + ClearAllErrors(); + IsChanged = false; + } + + public bool IsChanged { get; private set; } + + #endregion + + #region + + private bool inEdit; + public void BeginEdit() + { + if (inEdit) return; + inEdit = true; + SetProperties(_backup); + } + + public void CancelEdit() + { + if (!inEdit) return; + inEdit = false; + CancelChanges(); + } + + public void EndEdit() + { + if (!inEdit) return; + inEdit = false; + SetProperties(_backup); + } + + #endregion + + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightValidation/ViewModels/ViewModelBase.cs Sat Apr 21 15:06:48 2012 +0100 @@ -0,0 +1,73 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; + +namespace SilverlightValidation.ViewModels +{ + public class ViewModelBase : INotifyPropertyChanged, INotifyDataErrorInfo + { + #region INotifyPropertyChanged method plus event + + public event PropertyChangedEventHandler PropertyChanged = delegate { }; + + protected void RaisePropertyChanged(string propertyName) + { + PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); + } + + #endregion + + #region INotifyDataErrorInfo methods and helpers + + private readonly Dictionary<string, List<string>> _errors = new Dictionary<string, List<string>>(); + + public void SetError(string propertyName, string errorMessage) + { + if (!_errors.ContainsKey(propertyName)) + _errors.Add(propertyName, new List<string> { errorMessage }); + + RaiseErrorsChanged(propertyName); + } + + protected void ClearError(string propertyName) + { + if (_errors.ContainsKey(propertyName)) + { + _errors.Remove(propertyName); + RaiseErrorsChanged(propertyName); + } + } + + protected void ClearAllErrors() + { + var errors = _errors.Select(error => error.Key).ToList(); + + foreach (var propertyName in errors) + ClearError(propertyName); + } + + public void RaiseErrorsChanged(string propertyName) + { + ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName)); + } + + public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged = delegate { }; + + public IEnumerable GetErrors(string propertyName) + { + if (propertyName == null) return null; + return _errors.ContainsKey(propertyName) + ? _errors[propertyName] + : null; + } + + public bool HasErrors + { + get { return _errors.Count > 0; } + } + + #endregion + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightValidation/Views/UserListView.xaml Sat Apr 21 15:06:48 2012 +0100 @@ -0,0 +1,83 @@ +<UserControl x:Class="SilverlightValidation.Views.UserListView" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:p="clr-namespace:System.Windows.Controls.Primitives;assembly=System.Windows.Controls" + xmlns:s="clr-namespace:System;assembly=mscorlib" + xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" + d:DesignHeight="400" + d:DesignWidth="725" + mc:Ignorable="d"> + + <Grid x:Name="LayoutRoot" Background="White"> + <Grid.RowDefinitions> + <RowDefinition Height="30" /> + <RowDefinition Height="40" /> + <RowDefinition Height="300" /> + <RowDefinition Height="50" /> + </Grid.RowDefinitions> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="*" /> + <ColumnDefinition Width="725" /> + <ColumnDefinition Width="*" /> + </Grid.ColumnDefinitions> + + <StackPanel Grid.Row="1" + Grid.Column="1" + HorizontalAlignment="Right" + Orientation="Horizontal"> + <Button Width="60" + Command="AddCommand" + Content="Add" + Style="{StaticResource ButtonStyle}" /> + <Button Width="60" + Command="{Binding CancelCommand}" + Content="Delete" + Style="{StaticResource ButtonStyle}" /> + </StackPanel> + + <controls:DataGrid Grid.Row="2" + Grid.Column="1" + AutoGenerateColumns="False" + ItemsSource="{Binding Data}" + SelectedItem="{Binding SelectedItem}"> + <controls:DataGrid.Columns> + <controls:DataGridTextColumn Width="125" + Binding="{Binding Username, + Mode=TwoWay, + ValidatesOnNotifyDataErrors=True, + NotifyOnValidationError=True}" + Header="Username" /> + <controls:DataGridTemplateColumn Width="125" Header="Password"> + <sdk:DataGridTemplateColumn.CellTemplate> + <DataTemplate> + <PasswordBox Password="{Binding Password, Mode=TwoWay, ValidatesOnNotifyDataErrors=True, NotifyOnValidationError=True}" /> + </DataTemplate> + </sdk:DataGridTemplateColumn.CellTemplate> + </controls:DataGridTemplateColumn> + <controls:DataGridTextColumn Width="150" + Binding="{Binding Email, + Mode=TwoWay, + ValidatesOnNotifyDataErrors=True, + NotifyOnValidationError=True}" + Header="Email" /> + + <controls:DataGridTemplateColumn Width="150" Header="Date of Birth"> + <sdk:DataGridTemplateColumn.CellTemplate> + <DataTemplate> + <sdk:DatePicker KeyDown="DatePicker_KeyDown" SelectedDate="{Binding DateOfBirth, Mode=TwoWay, ValidatesOnNotifyDataErrors=True, NotifyOnValidationError=True}" /> + </DataTemplate> + </sdk:DataGridTemplateColumn.CellTemplate> + </controls:DataGridTemplateColumn> + <controls:DataGridTextColumn Width="150" + Binding="{Binding Description, + Mode=TwoWay, + ValidatesOnNotifyDataErrors=True, + NotifyOnValidationError=True}" + Header="Description" /> + </controls:DataGrid.Columns> + </controls:DataGrid> + </Grid> +</UserControl>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightValidation/Views/UserListView.xaml.cs Sat Apr 21 15:06:48 2012 +0100 @@ -0,0 +1,28 @@ +using System.Windows.Browser; +using System.Windows.Input; +using SilverlightValidation.Data; +using SilverlightValidation.ViewModels; +using SilverlightValidation.Validators; + +namespace SilverlightValidation.Views +{ + public partial class UserListView + { + private UserListViewModel vm; + + public UserListView() + { + InitializeComponent(); + HtmlPage.Document.SetProperty("title", "Silverlight Validation"); + + vm = new UserListViewModel(Factory.CreateUserModels(), new UserModelValidator()); + this.DataContext = vm; + } + + private void DatePicker_KeyDown(object sender, KeyEventArgs e) + { + if (e.Key != Key.Tab) + e.Handled = true; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightValidation/Views/UserView.xaml Sat Apr 21 15:06:48 2012 +0100 @@ -0,0 +1,145 @@ +<UserControl x:Class="SilverlightValidation.Views.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:p="clr-namespace:System.Windows.Controls.Primitives;assembly=System.Windows.Controls" + xmlns:s="clr-namespace:System;assembly=mscorlib" + xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" + d:DesignHeight="400" + d:DesignWidth="450" + 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="150" /> + </Grid.RowDefinitions> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="*" /> + <ColumnDefinition Width="100" /> + <ColumnDefinition Width="300" /> + <ColumnDefinition Width="30" /> + <ColumnDefinition Width="*" /> + </Grid.ColumnDefinitions> + + <TextBlock Grid.Row="1" + Grid.Column="1" + Style="{StaticResource LabelStyle}" + Text="Username:" /> + + <TextBox x:Name="tbUsername" + Grid.Row="1" + Grid.Column="2" + LostFocus="tbUsername_LostFocus" + Style="{StaticResource TextBoxStyle}" + Text="{Binding Username, + Mode=TwoWay, + ValidatesOnNotifyDataErrors=True, + NotifyOnValidationError=True}" /> + + <sdk:DescriptionViewer Grid.Row="1" + Grid.Column="3" + Width="20" + Description="Required" + Target="{Binding ElementName=tbUsername}" /> + + <TextBlock Grid.Row="2" + Grid.Column="1" + Style="{StaticResource LabelStyle}" + Text="Password:" /> + + <PasswordBox x:Name="tbPassword" + Grid.Row="2" + Grid.Column="2" + LostFocus="tbPassword_LostFocus" + Password="{Binding Password, + Mode=TwoWay, + ValidatesOnNotifyDataErrors=True, + NotifyOnValidationError=True}" + Style="{StaticResource PasswordBoxStyle}" /> + + <sdk:DescriptionViewer Grid.Row="2" + Grid.Column="3" + Width="20" + Description="Required" + Target="{Binding ElementName=tbPassword}" /> + + <TextBlock Grid.Row="3" + Grid.Column="1" + Style="{StaticResource LabelStyle}" + Text="Email:" /> + + <TextBox x:Name="tbEmail" + Grid.Row="3" + Grid.Column="2" + LostFocus="tbEmail_LostFocus" + Style="{StaticResource TextBoxStyle}" + Text="{Binding Email, + Mode=TwoWay, + ValidatesOnNotifyDataErrors=True, + NotifyOnValidationError=True}" /> + + <sdk:DescriptionViewer Grid.Row="3" + Grid.Column="3" + Width="20" + Description="Required" + Target="{Binding ElementName=tbEmail}" /> + + <TextBlock Grid.Row="4" + Grid.Column="1" + Style="{StaticResource LabelStyle}" + Text="Date of Birth:" /> + + <sdk:DatePicker x:Name="dpDateOfBirth" + Grid.Row="4" + Grid.Column="2" + KeyDown="DatePicker_KeyDown" + LostFocus="dpDateOfBirth_LostFocus" + SelectedDate="{Binding DateOfBirth, + Mode=TwoWay, + ValidatesOnNotifyDataErrors=True, + NotifyOnValidationError=True}" + Style="{StaticResource DatePickerStyle}" /> + <sdk:DescriptionViewer Grid.Row="4" + Grid.Column="3" + Width="20" + Description="Required" + Target="{Binding ElementName=dpDateOfBirth}" /> + + <TextBlock x:Name="tbDescription" + Grid.Row="5" + Grid.Column="1" + Style="{StaticResource LabelStyle}" + Text="Description:" /> + + <TextBox Grid.Row="5" + Grid.Column="2" + Style="{StaticResource TextBoxStyle}" + Text="{Binding Description}" /> + <StackPanel Grid.Row="6" + Grid.Column="2" + HorizontalAlignment="Right" + Orientation="Horizontal"> + <Button Command="{Binding OkCommand}" + Content="OK" + Style="{StaticResource ButtonStyle}" /> + <Button Command="{Binding CancelCommand}" + Content="Cancel" + Style="{StaticResource ButtonStyle}" /> + </StackPanel> + + <sdk:ValidationSummary Grid.Row="7" + Grid.Column="1" + Grid.ColumnSpan="2" + Style="{StaticResource ValidationSummaryStyle}" /> + + </Grid> +</UserControl>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SilverlightValidation/SilverlightValidation/Views/UserView.xaml.cs Sat Apr 21 15:06:48 2012 +0100 @@ -0,0 +1,58 @@ +using System.Windows; +using System.Windows.Browser; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Input; +using SilverlightValidation.ViewModels; +using SilverlightValidation.Models; +using SilverlightValidation.Validators; + +namespace SilverlightValidation.Views +{ + public partial class UserView + { + private UserViewModel vm; + public UserView() + { + InitializeComponent(); + HtmlPage.Document.SetProperty("title", "Silverlight Validation"); + + vm = new UserViewModel(UserModel.Create(), new UserModelValidator()); + this.DataContext = vm; + } + + private static void UpdateTextBoxSource(object sender) + { + BindingExpression be = ((TextBox)sender).GetBindingExpression(TextBox.TextProperty); + be.UpdateSource(); + } + + private void DatePicker_KeyDown(object sender, KeyEventArgs e) + { + if (e.Key != Key.Tab) + e.Handled = true; + } + + private void tbUsername_LostFocus(object sender, RoutedEventArgs e) + { + UpdateTextBoxSource(sender); + } + + private void tbPassword_LostFocus(object sender, RoutedEventArgs e) + { + BindingExpression be = ((PasswordBox)sender).GetBindingExpression(PasswordBox.PasswordProperty); + be.UpdateSource(); + } + + private void tbEmail_LostFocus(object sender, RoutedEventArgs e) + { + UpdateTextBoxSource(sender); + } + + private void dpDateOfBirth_LostFocus(object sender, RoutedEventArgs e) + { + BindingExpression be = ((DatePicker)sender).GetBindingExpression(DatePicker.SelectedDateProperty); + be.UpdateSource(); + } + } +} \ No newline at end of file