Commit 6af9bf7

Craig Anderson <canderson@arcresources.com>
2010-10-18 17:37:27
added validation.
1 parent 738c025
src/MVPtoMVVM.mvvm/viewmodels/IValidation.cs
@@ -0,0 +1,8 @@
+namespace MVPtoMVVM.mvvm.viewmodels
+{
+    public interface IValidation
+    {
+        bool IsValid { get; }
+        string Message { get;  }
+    }
+}
\ No newline at end of file
src/MVPtoMVVM.mvvm/viewmodels/ToDoItemViewModel.cs
@@ -1,12 +1,14 @@
 using System;
+using System.Collections.Generic;
 using System.ComponentModel;
-using System.Windows.Input;
+using System.Text;
 using MVPtoMVVM.domain;
 using MVPtoMVVM.repositories;
+using System.Linq;
 
 namespace MVPtoMVVM.mvvm.viewmodels
 {
-    public class TodoItemViewModel : INotifyPropertyChanged
+    public class TodoItemViewModel : INotifyPropertyChanged, IDataErrorInfo
     {
         private readonly ITodoItemRepository todoItemRepository;
         private Synchronizer<TodoItemViewModel> updater;
@@ -17,6 +19,11 @@ namespace MVPtoMVVM.mvvm.viewmodels
             SaveCommand = new SimpleCommand(Save, CanSave);
             DeleteCommand = new SimpleCommand(Delete);
             updater = new Synchronizer<TodoItemViewModel>(PropertyChanged);
+            validations = new Dictionary<string, IValidation>
+                              {
+                                  {"Description", new Validation(() => !string.IsNullOrEmpty(Description), "Cannot have an empty description.")},
+                                  {"DueDate", new Validation(() => DueDate >= DateTime.Now, "Due Date must occur on or after today.")}
+                              };
         }
 
         private void Delete()
@@ -28,7 +35,7 @@ namespace MVPtoMVVM.mvvm.viewmodels
 
         private bool CanSave()
         {
-            return !string.IsNullOrEmpty(Description) && DueDate >= DateTime.Today;
+            return validations.Values.All(x => x.IsValid);
         }
 
         private void Save()
@@ -54,6 +61,8 @@ namespace MVPtoMVVM.mvvm.viewmodels
         }
 
         private DateTime dueDate;
+        private IDictionary<string, IValidation> validations;
+
         public DateTime DueDate
         {
             get { return dueDate; }
@@ -66,5 +75,32 @@ namespace MVPtoMVVM.mvvm.viewmodels
         public IObservableCommand SaveCommand { get; set; }
         public IObservableCommand DeleteCommand { get; set; }
         public MainWindowViewModel Parent { get; set; }
+
+        public string this[string columnName]
+        {
+            get
+            {
+                var validation = validations[columnName];
+                return validation.IsValid ? null : validation.Message;
+            }
+        }
+
+        public string Error
+        {
+            get { return BuildErrors(); }
+        }
+
+        private string BuildErrors()
+        {
+            var builder = new StringBuilder();
+            foreach (var validation in validations.Values)
+            {
+                if(!validation.IsValid)
+                {
+                    builder.AppendLine(validation.Message);
+                }
+            }
+            return builder.ToString();
+        }
     }
 }
\ No newline at end of file
src/MVPtoMVVM.mvvm/viewmodels/Validation.cs
@@ -0,0 +1,22 @@
+using System;
+
+namespace MVPtoMVVM.mvvm.viewmodels
+{
+    class Validation : IValidation
+    {
+        private Func<bool> Condition;
+
+        public Validation(Func<bool> condition, string message)
+        {
+            Condition = condition;
+            Message = message;
+        }
+
+        public bool IsValid
+        {
+            get { return Condition(); }
+        }
+
+        public string Message { get;set;}
+    }
+}
\ No newline at end of file
src/MVPtoMVVM.mvvm/MainWindow.xaml
@@ -3,12 +3,23 @@
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         Title="MainWindow" Height="350" Width="525">
     <DockPanel LastChildFill="False">
-        <ListView DockPanel.Dock="Top" ItemsSource="{Binding Path=TodoItems}" >
+        <DockPanel.Resources>
+        <Style x:Key="ValidationStyle" TargetType="Control">
+        <Style.Triggers>
+            <Trigger Property="Validation.HasError" Value="true">
+                <Setter Property="Control.ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)[0].ErrorContent}" />
+                <Setter Property="Control.BorderBrush" Value="Red" />
+                <Setter Property="Control.BorderThickness" Value="2" />
+            </Trigger>
+        </Style.Triggers>
+        </Style>
+        </DockPanel.Resources>
+        <ListView DockPanel.Dock="Top" ItemsSource="{Binding Path=TodoItems}">
             <ListView.ItemTemplate>
                 <DataTemplate>
                 <StackPanel Orientation="Horizontal">
-                    <TextBox Width="200" Text="{Binding Path=Description}" />
-                    <DatePicker SelectedDate="{Binding Path=DueDate}" />
+                    <TextBox Width="200" Text="{Binding Path=Description, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" Style="{StaticResource ResourceKey=ValidationStyle}" />
+                    <DatePicker SelectedDate="{Binding Path=DueDate, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" Style="{StaticResource ResourceKey=ValidationStyle}" />
                     <Button Content="Save" Command="{Binding Path=SaveCommand}"></Button>
                     <Button Content="Del" Command="{Binding Path=DeleteCommand}"></Button>
                 </StackPanel>
src/MVPtoMVVM.mvvm/MVPtoMVVM.mvvm.csproj
@@ -61,10 +61,12 @@
     </ApplicationDefinition>
     <Compile Include="Bootstrap.cs" />
     <Compile Include="viewmodels\IObservableCommand.cs" />
+    <Compile Include="viewmodels\IValidation.cs" />
     <Compile Include="viewmodels\MainWindowViewModel.cs" />
     <Compile Include="viewmodels\SimpleCommand.cs" />
     <Compile Include="viewmodels\Synchronizer.cs" />
     <Compile Include="viewmodels\ToDoItemViewModel.cs" />
+    <Compile Include="viewmodels\Validation.cs" />
     <Page Include="MainWindow.xaml">
       <Generator>MSBuild:Compile</Generator>
       <SubType>Designer</SubType>