Ever since I wrote Animated Height Behavior, I wanted to create Behavior that will give me nice eye-candy for all my IDataErrorInfo validation needs. You can see the result in the video below, as well as the code of the Behavior. Please note that the image I’m using here is from the Resources (just add 16×16 png image to Resources and name it Error16). GetBitmapSource() is Extension that I wrote for converting System.Drawing.Bitmap to BitmapSource.
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;
using System.Windows.Media;
using System.Windows.Media.Animation;
namespace Foo
{
public class AnimatedErrorInfoBehavior : Behavior<FrameworkElement>
{
private readonly TextBlock textBlock_;
private Grid errorGrid_;
private readonly DoubleAnimation increaseHeightAnimation_;
private readonly Storyboard increaseHeightStoryboard_;
private readonly DoubleAnimation showAnimation_;
private readonly Storyboard showStoryboard_;
private readonly DoubleAnimation decreaseHeightAnimation_;
private readonly Storyboard descreaseHeightStoryboard_;
private readonly DoubleAnimation hideAnimation_;
private readonly Storyboard hideStoryboard_;
private readonly Dictionary<string, int> errors_;
public AnimatedErrorInfoBehavior()
{
errors_ = new Dictionary<string, int>();
textBlock_ = new TextBlock();
increaseHeightAnimation_ = new DoubleAnimation(
0.0,
23.0,
TimeSpan.FromMilliseconds(200)
);
increaseHeightAnimation_.EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut };
increaseHeightStoryboard_ = new Storyboard();
Storyboard.SetTarget(increaseHeightAnimation_, errorGrid_);
Storyboard.SetTargetProperty(increaseHeightAnimation_, new PropertyPath(FrameworkElement.HeightProperty));
increaseHeightStoryboard_.Children.Add(increaseHeightAnimation_);
showAnimation_ = new DoubleAnimation(0.0, 1.0, TimeSpan.FromMilliseconds(200));
showAnimation_.EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseIn };
showStoryboard_ = new Storyboard();
Storyboard.SetTarget(showAnimation_, textBlock_);
Storyboard.SetTargetProperty(showAnimation_, new PropertyPath(UIElement.OpacityProperty));
showStoryboard_.Children.Add(showAnimation_);
decreaseHeightAnimation_ = new DoubleAnimation(
23.0,
0.0,
TimeSpan.FromMilliseconds(100)
);
descreaseHeightStoryboard_ = new Storyboard();
Storyboard.SetTarget(decreaseHeightAnimation_, errorGrid_);
Storyboard.SetTargetProperty(decreaseHeightAnimation_, new PropertyPath(FrameworkElement.HeightProperty));
descreaseHeightStoryboard_.Children.Add(decreaseHeightAnimation_);
hideAnimation_ = new DoubleAnimation(1.0, 0.0, TimeSpan.FromMilliseconds(100));
hideAnimation_.EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut };
hideStoryboard_ = new Storyboard();
Storyboard.SetTarget(hideAnimation_, textBlock_);
Storyboard.SetTargetProperty(hideAnimation_, new PropertyPath(UIElement.OpacityProperty));
hideStoryboard_.Children.Add(hideAnimation_);
}
protected override void OnAttached()
{
var parent = VisualTreeHelper.GetParent(AssociatedObject) as Grid;
if (parent == null)
return;
var row_index = Grid.GetRow(AssociatedObject);
var row_span = Grid.GetRowSpan(AssociatedObject);
var column_index = Grid.GetColumn(AssociatedObject);
var column_span = Grid.GetColumnSpan(AssociatedObject);
parent.Children.Remove(AssociatedObject);
var grid = new Grid();
grid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
grid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
Grid.SetRow(grid, row_index);
Grid.SetRowSpan(grid, row_span);
Grid.SetColumn(grid, column_index);
Grid.SetColumnSpan(grid, column_span);
grid.Children.Add(AssociatedObject);
Grid.SetRow(AssociatedObject, 0);
errorGrid_ = new Grid();
errorGrid_.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Auto });
errorGrid_.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) });
errorGrid_.Height = 0;
var image = new Image();
image.Source = Resources.Error16.GetBitmapSource();
image.Margin = new Thickness(0,0,2,7);
errorGrid_.Children.Add(image);
Grid.SetColumn(image, 0);
textBlock_.Foreground = Brushes.Red;
errorGrid_.Children.Add(textBlock_);
Grid.SetColumn(textBlock_, 1);
grid.Children.Add(errorGrid_);
Grid.SetRow(errorGrid_, 1);
parent.Children.Add(grid);
Validation.AddErrorHandler(AssociatedObject, OnError);
Validation.SetErrorTemplate(AssociatedObject, null);
base.OnAttached();
}
private void OnError(object sender, ValidationErrorEventArgs e)
{
var error_msg = e.Error.ErrorContent.ToString();
if (e.Action == ValidationErrorEventAction.Added)
{
if (errors_.ContainsKey(error_msg))
errors_[error_msg]++;
else
errors_.Add(error_msg, 1);
if (errors_[error_msg] == 1)
{
textBlock_.Text = e.Error.ErrorContent.ToString();
increaseHeightStoryboard_.Begin(errorGrid_);
showStoryboard_.Begin(textBlock_);
}
}
if (e.Action == ValidationErrorEventAction.Removed)
{
errors_[error_msg]--;
if (errors_[error_msg] == 0)
{
descreaseHeightStoryboard_.Begin(errorGrid_);
hideStoryboard_.Begin(textBlock_);
}
}
}
}
}
Advertisement