changeset 73:d06c852e0167

looking good!
author Steven Hollidge <stevenhollidge@hotmail.com>
date Mon, 23 Apr 2012 19:15:52 +0100
parents 177a9d1eba10
children a79e235177f5
files SilverlightGlimpse/SilverlightGlimpse/Controls/FloatableWindow/FloatableWindow.cs SilverlightGlimpse/SilverlightGlimpse/Diagnostics/Stopwatch.cs SilverlightGlimpse/SilverlightGlimpse/Interfaces/IBrokenBindingsService.cs SilverlightGlimpse/SilverlightGlimpse/Interfaces/ILogWriter.cs SilverlightGlimpse/SilverlightGlimpse/Models/BindingError.cs SilverlightGlimpse/SilverlightGlimpse/Models/ValidationWrapper.cs SilverlightGlimpse/SilverlightGlimpse/Services/BrokenBindingsService.cs SilverlightGlimpse/SilverlightGlimpse/Services/Glimpse.cs SilverlightGlimpse/SilverlightGlimpse/Services/LogWriter.cs SilverlightGlimpse/SilverlightGlimpse/Services/Stopwatch.cs SilverlightGlimpse/SilverlightGlimpse/SilverlightGlimpse.csproj SilverlightGlimpse/SilverlightGlimpse/Views/BindingsViewer.xaml SilverlightGlimpse/SilverlightGlimpse/Views/ExceptionsViewer.xaml SilverlightGlimpse/SilverlightGlimpse/Views/ExceptionsViewer.xaml.cs SilverlightGlimpse/SilverlightGlimpse/Views/GlimpseViewer.xaml SilverlightGlimpse/SilverlightGlimpse/Views/ValidationsViewer.xaml SilverlightGlimpse/SilverlightGlimpse/Views/ValidationsViewer.xaml.cs
diffstat 17 files changed, 245 insertions(+), 239 deletions(-) [+]
line wrap: on
line diff
--- a/SilverlightGlimpse/SilverlightGlimpse/Controls/FloatableWindow/FloatableWindow.cs	Mon Apr 23 17:57:21 2012 +0100
+++ b/SilverlightGlimpse/SilverlightGlimpse/Controls/FloatableWindow/FloatableWindow.cs	Mon Apr 23 19:15:52 2012 +0100
@@ -634,7 +634,7 @@
             z++;
             Canvas.SetZIndex(this, z);
 #if DEBUG
-            this.Title = z.ToString();
+            //this.Title = z.ToString();
 #endif
         }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SilverlightGlimpse/SilverlightGlimpse/Diagnostics/Stopwatch.cs	Mon Apr 23 19:15:52 2012 +0100
@@ -0,0 +1,29 @@
+using System;
+
+namespace SilverlightGlimpse.Diagnostics
+{
+    public class Stopwatch
+    {
+        private long _start;
+        private long _end;
+
+        public void Start()
+        {
+            _start = DateTime.Now.Ticks;
+        }
+
+        public void Stop()
+        {
+            _end = DateTime.Now.Ticks;
+        }
+
+        public TimeSpan ElapsedTime { get { return new TimeSpan(_end - _start); }}
+
+        public static Stopwatch StartNew()
+        {
+            var stopwatch = new Stopwatch();
+            stopwatch.Start();
+            return stopwatch;
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SilverlightGlimpse/SilverlightGlimpse/Interfaces/IBrokenBindingsService.cs	Mon Apr 23 19:15:52 2012 +0100
@@ -0,0 +1,11 @@
+using System.Collections.Generic;
+using System.Windows;
+using SilverlightGlimpse.Models;
+
+namespace SilverlightGlimpse.Interfaces
+{
+    public interface IBrokenBindingsService
+    {
+        void LoadBrokenBindings(UIElement uiElement, IList<BindingError> bindingErrors);
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SilverlightGlimpse/SilverlightGlimpse/Interfaces/ILogWriter.cs	Mon Apr 23 19:15:52 2012 +0100
@@ -0,0 +1,9 @@
+using System.Collections;
+
+namespace SilverlightGlimpse.Interfaces
+{
+    public interface ILogWriter
+    {
+        void Write(IList log, int maxLogItems, string text, params object[] args);
+    }
+}
\ No newline at end of file
--- a/SilverlightGlimpse/SilverlightGlimpse/Models/BindingError.cs	Mon Apr 23 17:57:21 2012 +0100
+++ b/SilverlightGlimpse/SilverlightGlimpse/Models/BindingError.cs	Mon Apr 23 19:15:52 2012 +0100
@@ -13,7 +13,7 @@
         public BindingError(string controlName, string controlTypeName, string propertyName, string path)
         {
             _controlName = controlName;
-            ControlTypeName = controlTypeName;
+            ControlType = controlTypeName;
             PropertyName = propertyName;
             Path = path;
         }
@@ -23,7 +23,7 @@
         #region Properties
 
         public string ControlName { get { return string.IsNullOrEmpty(_controlName) ? "(none)" : _controlName; } }
-        public string ControlTypeName { get; private set; }
+        public string ControlType { get; private set; }
         public string Path { get; private set; }
         public string PropertyName { get; private set; }
         public string ToStringProperty { get { return ToString(); } }
@@ -37,7 +37,7 @@
             return string.Format(
                 "Control Name: {0}, Type: {1}, Property: {2}, Path: {3}",
                 ControlName,
-                ControlTypeName,
+                ControlType,
                 PropertyName,
                 Path);
         }
--- a/SilverlightGlimpse/SilverlightGlimpse/Models/ValidationWrapper.cs	Mon Apr 23 17:57:21 2012 +0100
+++ b/SilverlightGlimpse/SilverlightGlimpse/Models/ValidationWrapper.cs	Mon Apr 23 19:15:52 2012 +0100
@@ -9,11 +9,13 @@
         public ValidationWrapper(
             ValidationErrorEventAction enumAction,
             string controlName,
+            string controlType,
             string errorContent)
         {
             Action = enumAction;
             ControlName = controlName;
-            Message = errorContent;
+            ControlType = controlType;
+            ErrorContent = errorContent;
         }
 
         #endregion
@@ -22,7 +24,9 @@
 
         public ValidationErrorEventAction Action { get; private set; }
         public string ControlName { get; private set; }
-        public string Message { get; private set; }
+        public string ControlType { get; private set; }
+        public string ErrorContent { get; private set; }
+        public string ToStringProperty { get { return ToString(); } }
 
         #endregion
 
@@ -30,9 +34,15 @@
 
         public override string ToString()
         {
-            return string.Format("({0}) - {1}", Action, Message);
+            return string.Format(
+                "Validation Action: {0}, Name: {1} Type: {2}, ErrorContent: {3}",
+                Action,
+                ControlName,
+                ControlType,
+                ErrorContent);
         }
 
+
         #endregion
     }
 }
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SilverlightGlimpse/SilverlightGlimpse/Services/BrokenBindingsService.cs	Mon Apr 23 19:15:52 2012 +0100
@@ -0,0 +1,75 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Reflection;
+using System.Windows;
+using System.Windows.Media;
+using SilverlightGlimpse.Interfaces;
+using SilverlightGlimpse.Models;
+
+namespace SilverlightGlimpse.Services
+{
+    public class BrokenBindingsService : IBrokenBindingsService
+    {
+        public void LoadBrokenBindings(UIElement uiElement, IList<BindingError> bindingErrors)
+        {
+            var frameworkElement = uiElement as FrameworkElement;
+            if (frameworkElement == null) return;
+
+            foreach (var fieldInfo in frameworkElement.GetType().GetFields(BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Static))
+            {
+                if (!ReferenceEquals(fieldInfo.FieldType, typeof(DependencyProperty))) continue;
+
+                var bindingExpression = frameworkElement.GetBindingExpression((DependencyProperty)fieldInfo.GetValue(null));
+
+                if (bindingExpression == null || bindingExpression.ParentBinding.Source != null ||
+                    bindingExpression.ParentBinding.RelativeSource != null) continue;
+
+                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.CompareOrdinal(propertyInfo.Name, bindingExpression.ParentBinding.Path.Path) != 0) continue;
+                        isInherited = true;
+                        break;
+                    }
+                }
+
+                if (isInherited) break;
+
+                //this code handles empty bindings on the Button controls
+                // unsure as to why the Button has an empty or unresolved binding of textblock type...
+                if ((frameworkElement.Name == "")
+                    && (frameworkElement.GetType().Name == "TextBlock")
+                    && (fieldInfo.Name == "TextProperty")
+                    && (bindingExpression.ParentBinding.Path.Path == ""))
+                {
+                    continue;
+                }
+
+                var brokenBinding = new BindingError(
+                    frameworkElement.Name,
+                    frameworkElement.GetType().Name,
+                    fieldInfo.Name,
+                    bindingExpression.ParentBinding.Path.Path);
+
+                bindingErrors.Add(brokenBinding);
+                Debug.WriteLine("Broken Binding: {0}", brokenBinding);
+            }
+
+            int children = VisualTreeHelper.GetChildrenCount(frameworkElement);
+
+            for (int j = 0; j <= children - 1; j++)
+            {
+                var child = VisualTreeHelper.GetChild(frameworkElement, j) as FrameworkElement;
+
+                if (child != null)
+                {
+                    LoadBrokenBindings(child, bindingErrors);
+                }
+            }
+        }
+    }
+}
--- a/SilverlightGlimpse/SilverlightGlimpse/Services/Glimpse.cs	Mon Apr 23 17:57:21 2012 +0100
+++ b/SilverlightGlimpse/SilverlightGlimpse/Services/Glimpse.cs	Mon Apr 23 19:15:52 2012 +0100
@@ -1,10 +1,11 @@
 using System;
 using System.Collections.ObjectModel;
 using System.Diagnostics;
-using System.Reflection;
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Threading;
+using SilverlightGlimpse.Diagnostics;
+using SilverlightGlimpse.Interfaces;
 using SilverlightGlimpse.Views;
 using SilverlightGlimpse.Models;
 using System.Windows.Media;
@@ -19,24 +20,27 @@
         private DispatcherTimer _refreshBindingCountTimer;
         private static readonly TimeSpan FiveSeconds = new TimeSpan(0, 0, 0, 5);
         private const int MAX_LOG_ITEMS = 5;
-
+        private readonly ILogWriter _logWriter;
+        private readonly IBrokenBindingsService _brokenBindingsService;
         #endregion
 
         #region Private constructor
 
-        private Glimpse()
+        private Glimpse(ILogWriter logWriter, IBrokenBindingsService brokenBindingsService)
         {
             BindingErrors = new ObservableCollection<BindingError>();
             ValidationErrors = new ObservableCollection<ValidationWrapper>();
             Exceptions = new ObservableCollection<Exception>();
             Log = new ObservableCollection<string>();
+            _logWriter = logWriter;
+            _brokenBindingsService = brokenBindingsService;
         }
 
         #endregion
 
         #region Properties
 
-        public static Glimpse Service { get { return _instance ?? (_instance = new Glimpse()); } }
+        public static Glimpse Service { get { return _instance ?? (_instance = new Glimpse(new LogWriter(), new BrokenBindingsService())); } }
         internal Application App { get; private set; }
         internal FloatableWindow GlimpseWindow { get; set;}
         internal string Title { get; set; }
@@ -60,13 +64,6 @@
 
         #endregion
 
-        private void WriteToLog(string text, params object[] args)
-        {
-            var date = DateTime.Now.ToString("HH:mm:ss.ffff");
-            Log.Add(string.Concat(date, "\t", string.Format(text, args)));
-            if (Log.Count > MAX_LOG_ITEMS) Log.RemoveAt(0);
-        }
-
         #region UI Creation and Loading
 
         public void DisplayLoadFailure(Application app, Exception ex, string title)
@@ -100,7 +97,7 @@
             if (Double.IsNaN(RootVisual.Width))
             {
                 //if the host control is autosized (consumes the browser window) then locate Glimpse in the top, left
-                GlimpseWindow.Show(5,5);
+                GlimpseWindow.Show();
             }
             else
             {
@@ -113,7 +110,7 @@
                 GlimpseWindow.Show(dblLeft, 10);
             }
 
-            LoadBrokenBindings(RootVisual);
+            _brokenBindingsService.LoadBrokenBindings(RootVisual, BindingErrors);
 
             _refreshBindingCountTimer = new DispatcherTimer();
             _refreshBindingCountTimer.Tick += RefreshBindingCountTimer_Tick;
@@ -123,71 +120,6 @@
 
         #endregion
 
-        #region Update broken bindings collection
-
-        private void LoadBrokenBindings(UIElement uiElement)
-        {
-            var frameworkElement = uiElement as FrameworkElement;
-            if (frameworkElement == null) return;
-
-            foreach (var fieldInfo in frameworkElement.GetType().GetFields(BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Static))
-            {
-                if (!ReferenceEquals(fieldInfo.FieldType, typeof(DependencyProperty))) continue;
-
-                var bindingExpression = frameworkElement.GetBindingExpression((DependencyProperty)fieldInfo.GetValue(null));
-
-                if (bindingExpression == null || bindingExpression.ParentBinding.Source != null ||
-                    bindingExpression.ParentBinding.RelativeSource != null) continue;
-
-                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.CompareOrdinal(propertyInfo.Name, bindingExpression.ParentBinding.Path.Path) != 0) continue;
-                        isInherited = true;
-                        break;
-                    }
-                }
-
-                if (isInherited) break;
-
-                //this code handles empty bindings on the Button controls
-                // unsure as to why the Button has an empty or unresolved binding of textblock type...
-                if ((frameworkElement.Name == "")
-                    && (frameworkElement.GetType().Name == "TextBlock")
-                    && (fieldInfo.Name == "TextProperty")
-                    && (bindingExpression.ParentBinding.Path.Path == ""))
-                {
-                    continue;
-                }
-
-                var brokenBinding = new BindingError(
-                    frameworkElement.Name,
-                    frameworkElement.GetType().Name,
-                    fieldInfo.Name,
-                    bindingExpression.ParentBinding.Path.Path);
-
-                BindingErrors.Add(brokenBinding);
-                Debug.WriteLine("Broken Binding: {0}", brokenBinding);
-            }
-
-            int children = VisualTreeHelper.GetChildrenCount(frameworkElement);
-
-            for (int j = 0; j <= children - 1; j++)
-            {
-                var child = VisualTreeHelper.GetChild(frameworkElement, j) as FrameworkElement;
-
-                if (child != null)
-                {
-                    LoadBrokenBindings(child);
-                }
-            }
-        }
-
-        #endregion
-
         #region Events handlers
 
         // Bindings
@@ -198,10 +130,10 @@
             _refreshBindingCountTimer.Stop();
 
             BindingErrors.Clear();
-            LoadBrokenBindings(RootVisual);
+            _brokenBindingsService.LoadBrokenBindings(RootVisual, BindingErrors);
 
             stopwatch.Stop();
-            WriteToLog("Refreshing the binding error count took {0} {1}", stopwatch.ElapsedTime.Milliseconds, "ms");
+            _logWriter.Write(Log, MAX_LOG_ITEMS, "Refreshing the binding errors took {0} {1}", stopwatch.ElapsedTime.Milliseconds, "ms");
 
             _refreshBindingCountTimer.Start();
         }
@@ -220,6 +152,7 @@
             ValidationErrors.Add(
                 new ValidationWrapper(
                     e.Action, 
+                    e.OriginalSource.GetType().ToString(),
                     controlName, 
                     e.Error.ErrorContent.ToString()));
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SilverlightGlimpse/SilverlightGlimpse/Services/LogWriter.cs	Mon Apr 23 19:15:52 2012 +0100
@@ -0,0 +1,16 @@
+using System;
+using System.Collections;
+using SilverlightGlimpse.Interfaces;
+
+namespace SilverlightGlimpse.Services
+{
+    public class LogWriter : ILogWriter
+    {
+        public void Write(IList log, int maxLogItems, string text, params object[] args)
+        {
+            var date = DateTime.Now.ToString("HH:mm:ss.ffff");
+            log.Add(string.Concat(date, "\t", string.Format(text, args)));
+            if (log.Count > maxLogItems) log.RemoveAt(0);
+        }
+    }
+}
--- a/SilverlightGlimpse/SilverlightGlimpse/Services/Stopwatch.cs	Mon Apr 23 17:57:21 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-using System;
-
-namespace SilverlightGlimpse.Services
-{
-    public class Stopwatch
-    {
-        private long _start;
-        private long _end;
-
-        public void Start()
-        {
-            _start = DateTime.Now.Ticks;
-        }
-
-        public void Stop()
-        {
-            _end = DateTime.Now.Ticks;
-        }
-
-        public TimeSpan ElapsedTime { get { return new TimeSpan(_end - _start); }}
-
-        public static Stopwatch StartNew()
-        {
-            var stopwatch = new Stopwatch();
-            stopwatch.Start();
-            return stopwatch;
-        }
-    }
-}
\ No newline at end of file
--- a/SilverlightGlimpse/SilverlightGlimpse/SilverlightGlimpse.csproj	Mon Apr 23 17:57:21 2012 +0100
+++ b/SilverlightGlimpse/SilverlightGlimpse/SilverlightGlimpse.csproj	Mon Apr 23 19:15:52 2012 +0100
@@ -70,9 +70,16 @@
     <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="Services\BrokenBindingsService.cs" />
+    <Compile Include="Interfaces\IBrokenBindingsService.cs" />
+    <Compile Include="Interfaces\ILogWriter.cs" />
+    <Compile Include="Services\LogWriter.cs" />
     <Compile Include="Views\BindingsViewer.xaml.cs">
       <DependentUpon>BindingsViewer.xaml</DependentUpon>
     </Compile>
+    <Compile Include="Views\ValidationsViewer.xaml.cs">
+      <DependentUpon>ValidationsViewer.xaml</DependentUpon>
+    </Compile>
     <Compile Include="Views\GlimpseViewer.xaml.cs">
       <DependentUpon>GlimpseViewer.xaml</DependentUpon>
     </Compile>
@@ -93,13 +100,17 @@
     <Compile Include="Models\ValidationWrapper.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Services\Glimpse.cs" />
-    <Compile Include="Services\Stopwatch.cs" />
+    <Compile Include="Diagnostics\Stopwatch.cs" />
   </ItemGroup>
   <ItemGroup>
     <Page Include="Views\BindingsViewer.xaml">
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
     </Page>
+    <Page Include="Views\ValidationsViewer.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </Page>
     <Page Include="Views\GlimpseViewer.xaml">
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
--- a/SilverlightGlimpse/SilverlightGlimpse/Views/BindingsViewer.xaml	Mon Apr 23 17:57:21 2012 +0100
+++ b/SilverlightGlimpse/SilverlightGlimpse/Views/BindingsViewer.xaml	Mon Apr 23 19:15:52 2012 +0100
@@ -10,8 +10,8 @@
         </Grid.RowDefinitions>
 
         <StackPanel Grid.Row="0" Orientation="Horizontal">
-            <TextBlock Width="145"
-                       Margin="7,0,0,0"
+            <TextBlock Width="120"
+                       Margin="10,0,0,0"
                        Text="Control Name" />
             <TextBlock Width="120" Text="Type" />
             <TextBlock Width="120" Text="Property" />
@@ -23,10 +23,10 @@
                 <ListBox.ItemTemplate>
                     <DataTemplate>
                         <StackPanel Orientation="Horizontal" ToolTipService.ToolTip="{Binding ToStringProperty}">
-                            <TextBlock Width="145" Text="{Binding ControlName}" />
+                            <TextBlock Width="120" Text="{Binding ControlName}" />
                             <TextBlock Width="120" Text="{Binding ControlTypeName}" />
                             <TextBlock Width="120" Text="{Binding PropertyName}" />
-                            <TextBlock Width="150" Text="{Binding Path}" />
+                            <TextBlock Text="{Binding Path}" />
                         </StackPanel>
                     </DataTemplate>
                 </ListBox.ItemTemplate>
--- a/SilverlightGlimpse/SilverlightGlimpse/Views/ExceptionsViewer.xaml	Mon Apr 23 17:57:21 2012 +0100
+++ b/SilverlightGlimpse/SilverlightGlimpse/Views/ExceptionsViewer.xaml	Mon Apr 23 19:15:52 2012 +0100
@@ -2,96 +2,6 @@
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
     <Grid x:Name="LayoutRoot">
-
-        <Grid.ColumnDefinitions>
-            <ColumnDefinition Width="225" />
-            <ColumnDefinition Width="*" />
-        </Grid.ColumnDefinitions>
-        <Grid.RowDefinitions>
-            <RowDefinition Height="Auto" />
-            <RowDefinition Height="*" />
-        </Grid.RowDefinitions>
-
-        <Grid Grid.Row="1">
-            <Grid.RowDefinitions>
-                <RowDefinition Height="*" />
-                <RowDefinition Height="Auto" />
-            </Grid.RowDefinitions>
-
-            <ListBox x:Name="lbExceptions"
-                     Margin="3.5"
-                     ItemsSource="{Binding}"
-                     SelectionChanged="lbExceptions_SelectionChanged" />
-
-            <Button Grid.Row="1"
-                    Width="135"
-                    Margin="7"
-                    HorizontalAlignment="Center"
-                    VerticalAlignment="Center"
-                    Click="ClearExceptions_Click"
-                    Content="Clear Exceptions" />
-        </Grid>
-        <ScrollViewer Grid.Row="1"
-                      Grid.Column="1"
-                      Margin="3.5"
-                      DataContext="{Binding ElementName=lbExceptions,
-                                            Path=SelectedItem}">
-            <Grid x:Name="gridExceptionDetail" Visibility="Collapsed">
-                <Grid.RowDefinitions>
-                    <RowDefinition Height="Auto" />
-                    <RowDefinition Height="Auto" />
-                    <RowDefinition Height="Auto" />
-                    <RowDefinition Height="Auto" />
-                </Grid.RowDefinitions>
-
-                <!--
-                    <TextBlock x:Name="tbAction"
-                    Text="Action"
-                    TextDecorations="Underline"
-                    Visibility="Collapsed" />
-                    
-                    <TextBlock Grid.Row="1"
-                    FontSize="11"
-                    Text="{Binding Path=Action}"
-                    TextWrapping="Wrap"
-                    Visibility="{Binding ElementName=tbAction,
-                    Path=Visibility}" />
-                    
-                    <TextBlock Grid.Row="2"
-                    Margin="0,7,0,0"
-                    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}" />
-                -->
-
-                <TextBlock Grid.Row="0"
-                           Margin="0,7,0,0"
-                           Text="Message"
-                           TextDecorations="Underline" />
-
-                <TextBlock Grid.Row="1"
-                           FontSize="11"
-                           Text="{Binding Path=Message}"
-                           TextWrapping="Wrap" />
-
-                <TextBlock Grid.Row="2"
-                           Margin="0,7,0,0"
-                           Text="Stack Trace"
-                           TextDecorations="Underline" />
-
-                <TextBlock Grid.Row="3"
-                           FontSize="11"
-                           Text="{Binding Path=StackTrace}"
-                           TextWrapping="Wrap" />
-
-            </Grid>
-        </ScrollViewer>
+        <ListBox x:Name="lbExceptions" ItemsSource="{Binding}" />
     </Grid>
 </UserControl>
--- a/SilverlightGlimpse/SilverlightGlimpse/Views/ExceptionsViewer.xaml.cs	Mon Apr 23 17:57:21 2012 +0100
+++ b/SilverlightGlimpse/SilverlightGlimpse/Views/ExceptionsViewer.xaml.cs	Mon Apr 23 19:15:52 2012 +0100
@@ -1,6 +1,4 @@
-using System.Windows;
-using System.Windows.Controls;
-using SilverlightGlimpse.Services;
+using SilverlightGlimpse.Services;
 
 namespace SilverlightGlimpse.Views 
 {
@@ -9,21 +7,7 @@
         public ExceptionsViewer()
         {
             InitializeComponent();
-            DataContext = Glimpse.Service.Exceptions;
-            if (Glimpse.Service.Exceptions.Count > 0)
-                lbExceptions.SelectedIndex = 0;
-        }
-
-        private void ClearExceptions_Click(object sender, RoutedEventArgs e)
-        {
-            Glimpse.Service.Exceptions.Clear();
-        }
-
-        private void lbExceptions_SelectionChanged(object sender, SelectionChangedEventArgs e)
-        {
-            gridExceptionDetail.Visibility = lbExceptions.SelectedItem == null
-                ? Visibility.Collapsed
-                : Visibility.Visible;
+            lbExceptions.ItemsSource = Glimpse.Service.Exceptions;
         }
     }
 }
\ No newline at end of file
--- a/SilverlightGlimpse/SilverlightGlimpse/Views/GlimpseViewer.xaml	Mon Apr 23 17:57:21 2012 +0100
+++ b/SilverlightGlimpse/SilverlightGlimpse/Views/GlimpseViewer.xaml	Mon Apr 23 19:15:52 2012 +0100
@@ -63,21 +63,21 @@
                     Content="Contract" />
 
             <c:TabControl Grid.Row="1"
-                          Width="800"
-                          Height="450">
+                          Width="600"
+                          Height="250">
 
-                <c:TabItem Header="Bindings">
+                <c:TabItem Header="Binding">
                     <views:BindingsViewer />
                 </c:TabItem>
-                <c:TabItem Header="Validation">
-                    <views:ExceptionsViewer />
-                </c:TabItem>
-                <c:TabItem Header="Exceptions">
-                    <views:ExceptionsViewer />
-                </c:TabItem>
                 <c:TabItem Header="Debug" Visibility="{Binding IsInDebugMode, Converter={local:BoolToVisibilityConverter FalseValue=Collapsed, TrueValue=Visible}}">
                     <views:LogViewer />
                 </c:TabItem>
+                <c:TabItem Header="Validation">
+                    <views:ValidationsViewer />
+                </c:TabItem>
+                <c:TabItem Header="Exception">
+                    <views:ExceptionsViewer />
+                </c:TabItem>
             </c:TabControl>
 
         </Grid>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SilverlightGlimpse/SilverlightGlimpse/Views/ValidationsViewer.xaml	Mon Apr 23 19:15:52 2012 +0100
@@ -0,0 +1,34 @@
+<UserControl x:Class="SilverlightGlimpse.Views.ValidationsViewer"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+    <Grid x:Name="LayoutRoot">
+        <Grid.RowDefinitions>
+            <RowDefinition Height="Auto" />
+            <RowDefinition Height="*" />
+        </Grid.RowDefinitions>
+
+        <StackPanel Grid.Row="0" Orientation="Horizontal">
+            <TextBlock Width="80"
+                       Margin="10,0,0,0"
+                       Text="Action" />
+            <TextBlock Width="120" Text="Control Name" />
+            <TextBlock Width="120" Text="Type" />
+            <TextBlock Width="150" Text="Error" />
+        </StackPanel>
+
+        <ScrollViewer Grid.Row="1">
+            <ListBox x:Name="lbValidationErrors">
+                <ListBox.ItemTemplate>
+                    <DataTemplate>
+                        <StackPanel Orientation="Horizontal" ToolTipService.ToolTip="{Binding ToStringProperty}">
+                            <TextBlock Width="80" Text="{Binding Action}" />
+                            <TextBlock Width="120" Text="{Binding ControlName}" />
+                            <TextBlock Width="120" Text="{Binding ControlType}" />
+                            <TextBlock Text="{Binding ErrorContent}" />
+                        </StackPanel>
+                    </DataTemplate>
+                </ListBox.ItemTemplate>
+            </ListBox>
+        </ScrollViewer>
+    </Grid>
+</UserControl>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SilverlightGlimpse/SilverlightGlimpse/Views/ValidationsViewer.xaml.cs	Mon Apr 23 19:15:52 2012 +0100
@@ -0,0 +1,13 @@
+using SilverlightGlimpse.Services;
+
+namespace SilverlightGlimpse.Views 
+{
+    public partial class ValidationsViewer
+    {
+        public ValidationsViewer()
+        {
+            InitializeComponent();
+            lbValidationErrors.ItemsSource = Glimpse.Service.ValidationErrors;
+        }
+    }
+}
\ No newline at end of file