Sunday 7 August 2011

Dynamic content button

What I’d like to present today is a control I struggled with during my first moments with WPF. The idea was to create a Button that will dynamically present particular content based on the text we’ve entered during design time. In this very case the content was supposed to be an image or a canvas.
First step is creating a style for our button, along with the control template inside:
<Style x:Key="ArrowRoundedButton" TargetType="{x:Type Button}">
  <Setter Property="HorizontalContentAlignment" Value="Center"/>
  <Setter Property="VerticalContentAlignment" Value="Center"/>
  <Setter Property="Template">
     <Setter.Value>
        <ControlTemplate TargetType="{x:Type Button}">
        </ControlTemplate>
     </Setter.Value>
  </Setter>
</Style> 
Now whatever we put inside of the ControlTemplate element is what our button's Content element will consist off. In our case it's going to be:
<Border Background="{TemplateBinding Background}" CornerRadius="5,5,5,5" x:Name="border1">
   <Grid>
      <TextBlock x:Name="textBlock" Text="{TemplateBinding Content}"
                 HorizontalAlignment="Center" VerticalAlignment="Center"/>
      <Viewbox x:Name="viewBox" Stretch="Fill" StretchDirection="Both">
         <Canvas Margin="8">
           <Path x:Name="Left" Stroke="White" StrokeThickness="2"
                 Data="M4,-4 L0,0 4,4 M0,-4 L-4,0 0,4" Visibility="Hidden"/>                                           
           <Path x:Name="SDown" Stroke="White" StrokeThickness="2" 
                 Data="M-4,-2 L0,2 4,-2" Visibility="Hidden" />
         </Canvas>
      </Viewbox>
   </Grid> 
</Border> 
Because we need to have a possibility to analyze the text entered into the Content at design time, we're adding a TextBlock/TextBox. Its Text property bound using the TemplateBinding to Content of the Button. Next we add a Viewbox, we need it in order to allow our control to be "stretchable" along with its insides. Viewbox is a really good control to use whenever scaling is required. Next, we're also adding a Path node with a name and Visibility property for some drawing.
The last step is adding some triggers to the ControlTemplate. With these triggers we will be able to control the visibility of the Path elements.
<ControlTemplate.Triggers>                       
   <Trigger Property="Text" SourceName="textBlock" Value="v">
      <Setter Property="Visibility" TargetName="textBlock" Value="Collapsed"/>
      <Setter Property="Visibility" TargetName="SDown" Value="Visible"/>
   </Trigger>
   <Trigger Property="Text" SourceName="textBlock" Value="&lt;&lt;">
      <Setter Property="Visibility" TargetName="textBlock" Value="Collapsed"/>
      <Setter Property="Visibility" TargetName="Left" Value="Visible"/>
   </Trigger>                        
</ControlTemplate.Triggers>
Now as you can see, based on the value we've entered into the Content, and through the binding into the TextBlock, we're setting the visibility of the element we want to display. If we type in text, we will see the unchanged button with text inside. If we define a value in the triggers section, we can dynamically change the looks of our button in design time.
A sample based on the code above: