Monday, January 5, 2015

Some experiences and ideas in coding Part 1

Points to be covered:


  • 1. Create a user control to simplify WPF forms. (this post)
  • 2. Use Strategy pattern in a complex decision making scenario.
  • 3. Converters
  • 4. Create a template to make form creations faster
  • 5. Create a common print template to print all forms in WPF



Create a user control to simplify WPF forms.

First define a style in your resource file:


 <!---MyDataForm Related Styles-->  
   <Style TargetType="{x:Type uc:MyDataForm}">  
     <Setter Property="ItemsPanel">  
       <Setter.Value>  
         <ItemsPanelTemplate>  
           <StackPanel Orientation="{Binding Orientation, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type uc:MyDataForm}}}"/>  
         </ItemsPanelTemplate>  
       </Setter.Value>  
     </Setter>  
     <Setter Property="Template">  
       <Setter.Value>  
         <ControlTemplate TargetType="{x:Type uc:MyDataForm}">  
           <Border Background="{TemplateBinding Background}"  
               BorderBrush="{TemplateBinding BorderBrush}"  
               BorderThickness="{TemplateBinding BorderThickness}">  
             <ItemsPresenter />  
           </Border>  
         </ControlTemplate>  
       </Setter.Value>  
     </Setter>  
   </Style>  
   <ControlTemplate x:Key="ConfirmationTemplate" TargetType="{x:Type uc:MyDataFormItem}">  
     <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Margin}">  
       <DockPanel LastChildFill="False">  
         <TextBlock Style="{DynamicResource TextGray13BoldLbl}" DockPanel.Dock="Top" Margin="10,1,0,0" Text="{Binding Path=(uc:MyDataFormItem.LabelText)}" />  
         <ContentPresenter Margin="10,0,0,0" />  
       </DockPanel>  
     </Border>  
   </ControlTemplate>  
   <ControlTemplate x:Key="EntryFormTemplate" TargetType="{x:Type uc:MyDataFormItem}">  
     <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Margin}">  
       <DockPanel LastChildFill="False">  
         <Label Style="{StaticResource NewDesignFormInputLabelStyle}" DockPanel.Dock="Bottom" Margin="5,1,0,0"   
                   Content="{Binding Path=(uc:MyDataFormItem.LabelText), Converter={StaticResource UpperCaseConv}}" />  
         <ContentPresenter Margin="2,0,0,0" />  
       </DockPanel>  
     </Border>  
   </ControlTemplate>  
   <Style TargetType="{x:Type uc:MyDataFormItem}">  
     <Setter Property="Template" Value="{StaticResource EntryFormTemplate}"/>  
     <Style.Triggers>  
       <DataTrigger Binding="{Binding Path=(uc:MyDataFormItem.IsConfirmation)}" Value="True">  
         <Setter Property="Template" Value="{StaticResource ConfirmationTemplate}"/>  
       </DataTrigger>  
       <DataTrigger Binding="{Binding Path=Visibility}" Value="Collapsed">  
         <Setter Property="Template">  
           <Setter.Value>  
             <ControlTemplate TargetType="{x:Type uc:MyDataFormItem}">  
               <Border Visibility="Collapsed"/>  
             </ControlTemplate>  
           </Setter.Value>  
         </Setter>  
       </DataTrigger>  
     </Style.Triggers>  
   </Style>  

Then create a class MyDataForm which is a user control:


  public class MyDataForm : ItemsControl  
   {  
     static MyDataForm()  
     {  
       DefaultStyleKeyProperty.OverrideMetadata(typeof(MyDataForm), new FrameworkPropertyMetadata(typeof(MyDataForm)));  
       IsTabStopProperty.OverrideMetadata(typeof(MyDataForm), new FrameworkPropertyMetadata(false));  
     }  
     public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register("Orientation", typeof(Orientation), typeof(MyDataForm), new FrameworkPropertyMetadata(Orientation.Vertical));  
     public Orientation Orientation  
     {  
       get { return (Orientation)GetValue(OrientationProperty); }  
       set  
       {  
         SetValue(OrientationProperty, value);  
       }  
     }  
     protected override bool IsItemItsOwnContainerOverride(object item)  
     {  
       return item is MyDataForm || item is MyDataFormItem;  
     }  
     protected override DependencyObject GetContainerForItemOverride()  
     {  
       return new MyDataFormItem();  
     }  
   }  



Then create a class MyDataFormItem which is a user control:


  public class MyDataFormItem : ContentControl  
  {  
     static MyDataFormItem()  
     {  
       DefaultStyleKeyProperty.OverrideMetadata(typeof(MyDataFormItem), new FrameworkPropertyMetadata(typeof(MyDataFormItem)));  
       IsTabStopProperty.OverrideMetadata(typeof(MyDataFormItem), new FrameworkPropertyMetadata(false));  
     }  
     public static readonly DependencyProperty LabelTextProperty = DependencyProperty.RegisterAttached("LabelText", typeof(string), typeof(MyDataFormItem));  
     public static string GetLabelText(DependencyObject obj)  
     {  
       return (string)obj.GetValue(LabelTextProperty);  
     }  
     public static void SetLabelText(DependencyObject obj, string value)  
     {  
       obj.SetValue(LabelTextProperty, value);  
     }  
     public static bool GetIsConfirmation(DependencyObject obj)  
     {  
       return (bool)obj.GetValue(IsConfirmationProperty);  
     }  
     public static void SetIsConfirmation(DependencyObject obj, bool value)  
     {  
       obj.SetValue(IsConfirmationProperty, value);  
     }  
     // Using a DependencyProperty as the backing store for IsConfirmation. This enables animation, styling, binding, etc...  
     public static readonly DependencyProperty IsConfirmationProperty =  
       DependencyProperty.RegisterAttached("IsConfirmation", typeof(bool), typeof(MyDataFormItem), new UIPropertyMetadata(false));  
 }  


Usage in XAML


 <TextBox uc:MyDataFormItem.LabelText="Contact name" x:Name="txtContactName" Text="{Binding ContactName}" TextWrapping="Wrap"></TextBox>  

Other points covered in other posts