Hi,
This is a little piece of code to display beautiful popups like errors for WPF with the pattern MVVM.
First the Behavior
Code:
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls.Primitives;
public class PopupBehavior
{
private static bool showOnActivated;
public static FrameworkElement GetReLocation(DependencyObject obj)
{
return (FrameworkElement)obj.GetValue(ReLocationProperty);
}
public static void SetReLocation(DependencyObject obj, FrameworkElement value)
{
obj.SetValue(ReLocationProperty, value);
}
public static readonly DependencyProperty ReLocationProperty = DependencyProperty.RegisterAttached(
"ReLocation",
typeof(FrameworkElement),
typeof(PopupBehavior),
new UIPropertyMetadata(OnReLocationPropertyChanged));
private static void OnReLocationPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
if (DesignerProperties.GetIsInDesignMode(obj))
{
return;
}
if (obj == null)
{
return;
}
var element = obj as UIElement;
if (element == null)
{
return;
}
var popup = args.NewValue as Popup;
if (popup == null)
{
return;
}
SetUpReLocation(element, popup);
}
private static void SetUpReLocation(UIElement element, Popup popup)
{
var window = Window.GetWindow(element);
if (null == window)
{
return;
}
window.LocationChanged += (sender, args) => RedrawPopup(popup);
window.SizeChanged += (sender, args) => RedrawPopup(popup);
window.Activated += (sender, args) => ActivatedPopup(popup);
window.Deactivated += (sender, args) => DeactivatedPopup(popup);
}
private static void RedrawPopup(Popup popup)
{
var offset = popup.HorizontalOffset;
popup.HorizontalOffset = offset + 1;
popup.HorizontalOffset = offset;
}
private static void ActivatedPopup(Popup popup)
{
if (!showOnActivated)
{
return;
}
popup.IsOpen = true;
showOnActivated = false;
}
private static void DeactivatedPopup(Popup popup)
{
if (!popup.IsOpen)
{
return;
}
popup.IsOpen = false;
showOnActivated = true;
}
}
This allow you to show, hide and more automatic interactivity with the popup of the error.
Now the template
Code:
<ControlTemplate x:Key="ErrorTemplate">
<Grid>
<Border x:Name="ErrorBorder" Background="#11FF0000" IsHitTestVisible="False"
BorderBrush="#FFCB2E2E" BorderThickness="1"
radEx:PopupBehavior.ReLocation="{Binding ElementName=ErrorPopup}"/>
<AdornedElementPlaceholder x:Name="Placeholder" />
<Popup x:Name="ErrorPopup"
AllowsTransparency="True"
HorizontalAlignment="Right"
HorizontalOffset="0"
VerticalOffset="0"
PopupAnimation="Fade"
Placement="Right"
PlacementTarget="{Binding ElementName=ErrorBorder}"
IsOpen="{Binding ElementName=Placeholder, Path=AdornedElement.IsFocused, Mode=OneWay}">
<StackPanel Orientation="Horizontal">
<Polygon VerticalAlignment="Center" Points="0,4 4,0 4,8" Fill="#FFCB2E2E"
Stretch="Fill" Stroke="#FFCB2E2E" StrokeThickness="2" />
<Border Background="#FFCB2E2E" CornerRadius="4" Padding="4">
<TextBlock HorizontalAlignment="Center" Foreground="White" FontWeight="Bold" Margin="2,0,0,0"
Text="{Binding ElementName=Placeholder, Path=AdornedElement.ToolTip, Mode=OneWay}" />
</Border>
</StackPanel>
</Popup>
</Grid>
</ControlTemplate>
Dont forget declare the namespace where you set the behavior
Code:
xmlns:radEx="clr-namespace:[TheNamespaceWhereYouDefineTheBehavior]"
Near to end we define the style, in this case for a TextBox
Code:
<Style x:Key="TextBoxError" TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBoxBase}}">
<Setter Property="Validation.ErrorTemplate" Value="{StaticResource ErrorTemplate}"/>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" />
</Trigger>
</Style.Triggers>
</Style>
And at the end apply this to a TextBox
Code:
<TextBox
Text="{Binding Path=MyMVMMText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, NotifyOnValidationError=True, ValidatesOnDataErrors=True}"
TextAlignment="Right"
Style="{StaticResource TextBoxError}"/>
Thats all for get nice error displays on controls.
Like all ControlTemplate can style any control.
Have a nice day!