Samstag, 17. Juli 2010

Silverlight: Dataform Required field data UI customizing

If you use a dataform with the autogenerate property set to true, you can customize the behaviour and the look and feel of the dataform in the OnAutoGeneratingField Event.

For example you can set the look and feel of required fields to your individual style.

1. step: DataAnnotation for your properties
   1:  
   2:             [Display(Name = "WKN", ResourceType = typeof(DataResources), Order = 7)]
   3:             [StringLength(6, ErrorMessageResourceName = "ValidationErrorStringTooLong", ErrorMessageResourceType = typeof(ErrorResources))]
   4:             [Required(ErrorMessageResourceName = "ValidationErrorRequiredField", ErrorMessageResourceType = typeof(ErrorResources))]
   5:             public string WKN { get; set; }


2. step: Override OnAutoGeneratingField

Define your own DataForm control which inherits from DataForm. Then you can override the OnAutoGeneratingField method and do a lot of tricky things. Manipulating the behaviour of your autogenerated datafields or give them a different style. In my example we used in our project this mechanism to attach a GotFocus and LostFocus-Event to each TextBox and DatePicker, if there is a Required-Attribute defined.

   1: RequiredAttribute requiredAttribute = (RequiredAttribute)(from Attribute a in customAttributes 
   2:                   where a is RequiredAttribute select a).FirstOrDefault();
   3:  
   4: if (requiredAttribute != null) 
   5: {
   6:     if ((e.Field.Content is TextBox) || (e.Field.Content is DatePicker))
   7:     {
   8:         ((Control)e.Field.Content).GotFocus += new RoutedEventHandler(BilanzObjektDataForm_GotFocus);
   9:         ((Control)e.Field.Content).LostFocus += new RoutedEventHandler(BilanzObjektDataForm_LostFocus);
  10:     }
  11: }

The GotFocus- and LostFocus-Events looks like this:

   1: void BilanzObjektDataForm_LostFocus(object sender, RoutedEventArgs e)
   2:         {
   3:             // State auf "kein" Pflichtfeld setzen.
   4:             // State "normal" kann nicht definiert werden, da dieser eindeutig benamt werden muss
   5:             VisualStateManager.GoToState((Control)sender, "NotRequired", true);
   6:         }
   1: void BilanzObjektDataForm_GotFocus(object sender, RoutedEventArgs e)
   2:         {
   3:             // die Pflichtfeld-Behandlung gilt nur für TextBox- und DatePicker-Controls
   4:             // und nur dann, wenn der Text leer ist
   5:             if (((sender is TextBox) && (String.IsNullOrEmpty(((TextBox)sender).Text))) || 
   6:                 ((sender is DatePicker) && (String.IsNullOrEmpty(((DatePicker)sender).Text))))
   7:             {
   8:                 // State auf Pflichtfeld setzen
   9:                 VisualStateManager.GoToState((Control)sender, "Required", true);
  10:             }
  11:         }

In this Eventhandlers we use the VisualStateManager to give the controls, if the content is empty, a new visual state “Required” or in the other case the visual state “NotRequired”.

Now you have only to define the two new states in your style and you can enjoy the new Required field effect.

3. step: Add new States to your style

In the VisualStateManager section:

   1: <VisualStateGroup x:Name="RequiredStates">
   2:                                <VisualState x:Name="NotRequired">
   3:                                    <Storyboard>
   4:                                        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="PflichtfeldInfo">
   5:                                            <EasingDoubleKeyFrame KeyTime="0" Value="0"/>                                            
   6:                                        </DoubleAnimationUsingKeyFrames>
   7:                                    </Storyboard>
   8:                                </VisualState>
   9:                                <VisualState x:Name="Required">
  10:                                    <Storyboard>
  11:                                        <Storyboard>
  12:                                            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="PflichtfeldInfo">                                                
  13:                                                <EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="1" >
  14:                                                    <EasingDoubleKeyFrame.EasingFunction>
  15:                                                        <CubicEase EasingMode="EaseOut"/>
  16:                                                    </EasingDoubleKeyFrame.EasingFunction>
  17:                                                </EasingDoubleKeyFrame>
  18:                                                <EasingDoubleKeyFrame KeyTime="0:0:2" Value="0"/>
  19:                                            </DoubleAnimationUsingKeyFrames>
  20:                                        </Storyboard>                                        
  21:                                    </Storyboard>
  22:                                </VisualState>
  23:                            </VisualStateGroup>

The content style:

   1: <Grid  >                              
   2:                                 <ScrollViewer x:Name="ContentElement" 
   3:                                               BorderThickness="0"
   4:                                               IsTabStop="False"
   5:                                               Margin="4,0,2,2"
   6:                                               VerticalAlignment="Center"  />
   7:                                 <TextBlock x:Name="PflichtfeldInfo"
   8:                                    Text="Pflichtfeld"
   9:                                    Style="{StaticResource PflichtfeldStyle}"
  10:                                    Opacity="0" />
  11:                             </Grid>                            
  12:                         </Grid>

Keine Kommentare:

Kommentar veröffentlichen