Showing posts with label Template. Show all posts
Showing posts with label Template. Show all posts

Sunday, July 4, 2010

Common Code Base 2 Styles and Templates

As everybody knows Silverlight doesn’t support the Triggers which are most common in WPF.That means we cannot use WPF styles as it is.So obviously we need to create new styles even for Silverlight 4 which are same in behavior but using different xaml.Below are the best practices which we can follow to tackle the styles and templates in Common Code Base  scenario.

  • Don’t write any inline styles.Use resource dictionaries.
  • Merge the resource dictionaries at the application level only.

This will solve the issue with basic styles.Think of a scenario where you are loading the styles dynamically.In WPF you can handle this using DynamicResource binding extension.But the sad thing is Silverlight doesn’t support DynamicResource. So what is the solution.
The solution which we applied was very easy.Use StaticResource in the XAML files and load the styles through code in the App.xaml.vb file.Yes it worked in WPF too.
Download sample from here to see the styles and templates in action in CCB.(See the foreground of Button.Its coming through Style)

Previous posts on Common Code Base
----------------------------------
Common Code Base 1 Introduction

Tuesday, May 19, 2009

WatermarkTextBox by inheriting TextBox

I am very happy to see that my previous post “WPF Watermark TextBox using XAML Style” helped a lot of peoples to solve their issues and currently that is the most popular post in my blog.That post describes about creating a WPF watermark textbox by changing it’s style.All the things are done in xaml and there is no property to set the water mark text.
There was a requirement from one of the readers for such a property.ie a Watermark property which decides the watermark text.So rewriting the sample with that property.
Here I just derived a new class called WatemarkTextBox from standard TextBox added a new dependency property called Watermark and defined default style for that control in generic.xaml.The steps are as follows

  1. Subclass TextBox and create a new class called WatermarkTextBox.
  2. Add a new DP called Watermark which is of type object.
  3. In the generic.xaml write the default style.
public class WatermarkTextBox : TextBox
{
static WatermarkTextBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(WatermarkTextBox),
new FrameworkPropertyMetadata(typeof(WatermarkTextBox)));
}

public object Watermark
{
get { return (object)GetValue(WatermarkProperty); }
set { SetValue(WatermarkProperty, value); }
}
// Using a DependencyProperty as the backing store for Watermark. This enables animation, styling, binding, etc...
public static readonly DependencyProperty WatermarkProperty = DependencyProperty.Register(
"Watermark",
typeof(object),
typeof(WatermarkTextBox),
new UIPropertyMetadata(null));
}

And its style in generic.xaml contains almost same elements as of my last post.But here I have used TemplateBinding to set Watermark into the TextBlock.

<Style TargetType="{x:Type local:WatermarkTextBox}">
<Setter Property="Foreground"
Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" />
<Setter Property="Background"
Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" />
<Setter Property="BorderBrush"
Value="Blue" />
<Setter Property="BorderThickness"
Value="1" />
<Setter Property="Padding"
Value="1" />
<Setter Property="AllowDrop"
Value="true" />
<Setter Property="FocusVisualStyle"
Value="{x:Null}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:WatermarkTextBox}">
<Grid>
<Microsoft_Windows_Themes:ListBoxChrome x:Name="Bd"
SnapsToDevicePixels="true"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
RenderFocused="{TemplateBinding IsKeyboardFocusWithin}"
RenderMouseOver="{TemplateBinding IsMouseOver}">
<ScrollViewer x:Name="PART_ContentHost"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Microsoft_Windows_Themes:ListBoxChrome>
<TextBlock x:Name="textBlock"
Opacity="0.345"
Text="{TemplateBinding Watermark}"
TextWrapping="Wrap"
Visibility="Hidden" />
</Grid>
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsFocused"
Value="False" />
<Condition Property="Text"
Value="" />
</MultiTrigger.Conditions>
<Setter Property="Visibility"
TargetName="textBlock"
Value="Visible" />
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Download sample from here.

Friday, February 13, 2009

Readymade XAML Styles and Templates

Designer free development in WPF
A great look and feel matters everywhere in WPF.If you had selected WPF for your project developement ,it's UI design should be stunning and excellent.
But what to do if there are no designers in your company ? Or the designers in your company don't have enough knowledge in XAML and Blend.Some time the project doesn't have enough budget to employ a designer.
Here comes the importance of ready made XAML Style packs and templates.Style packs or Xaml templates library means a collection of global Styles and templates for all standard controls which can be inserted in to your resource dictionary.Thus all your controls in that application will be in the same theme.
I just saw a site which provides these type of xaml templates.I think there will be some more companies or sites which provide ready made xaml assets.So the below list will grew as I come across new style pack providers.

Tuesday, February 10, 2009

Creating WPF Watermarked TextBox using Expression Blend

Here are the steps to create a watermarked TextBox in WPF using Expression Blend as I promised in my last post.

  1. Create a new WPF application in Expression Blend
    • Click on File menu
    • Then click on New Project.Select WPF Application
    • Name as "WaterMarkedTextBox"
  2. Create a TextBox control and set it's Text="".
  3. Now create a Button control .Button is to test the focus lost event of TextBox.
  4. Set the Width and Height of These controls in order to get displayed properly.
  5. Now edit the template of TextBox.
    • Right click on the TextBox shown in Objects and Timeline panel.
    • Select "Edit Control Parts (Template)"
    • Then select "Edit a copy"
      BlendWTB1
    • Select location and press "OK".
  6. Now put the ScrollViewer named "PART_ContentHost" into a grid
    • Right click on the ScrollViewer in Objects and TimeLine.

    • Select "Group into" then "Grid".
  7. Now add a TextBlock named "watermark" into the newly created Grid
    • Double click on the newly created Grid to select it.
    • Add a TextBlock.
    • Set its Text as "Enter here".
    • Set Visibility="Hidden".
    • Set Opacity=".35" ie 35%
  8. Now add a Multi Trigger which fires on the condition IsFocused="False" and Text=""It sets the visibility of TextBlock "watermark" to Visible.
    • Click on the "+ Property" Button in the interaction pan to create trigger.
    • Change the Property Name to "IsFocused" and Value to "False" in the first record of "Activated when" area.Don't change the target-element.
    • Now click on the "+" button available in the same row of "Activated when" to add one more condition.
    • In the new condition set property as Text and Value as "" ie empty string.Better leave value as it is.By default it will take the empty string.
    • Now select the watermark TextBlock.Set it's visibility.
      BlendWTB3
  9. Now the Template editing is over.Save and run the application.

N.B : It is recommended to see the generated XAML to ensure the output.The XAML may differ if you had clicked in wrong places.

Monday, February 9, 2009

WPF Watermark TextBox using XAML Style

What is watermarked TextBox



Watermarked TextBox is a special type of text input control which displays a message or image when it is empty.Usually the message will be "Enter the text" and sometimes it may be description about that data field.



When we click on the TextBox ie getting focus the watermark text ("Enter the text") will disappear and it will become an ordinary TextBox.



Developing Watermark TextBox



The tasks of developer are hiding the watermark on getting focus and showing again on lost focus, if the user doesn't entered value in that.ie if the TextBox is empty watermark should come again.



In earlier days this itself was a control which is inherited from normal TextBox.But with the help of Templating and Trigger support in WPF we could achieve it very easily without inheriting.Just by Stying and Templating an ordinary TextBox.



Structure of Watermark TextBox Style



The style can be based on the style of TextBox itself.This reduces our effort in implementing normal TextBox behaviors.We are just going to concentrate on Template.



The normal TextBox template contains a ScrollViewer to hold the data.We are just going to put a TextBlock over that which is going to hold the Watermark text("Enter the Text").By default the visibility of this new TextBlock will be hidden.



Inside ControlTemplate





<Grid>


    <ScrollViewer x:Name="PART_ContentHost"


                  SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />


    <TextBlock x:Name="textBlock"


               Opacity="0.345"


               Text="Enter Text Here"


               TextWrapping="Wrap"


               Visibility="Hidden" />


</Grid>





Now we write Trigger to  show this TextBlock on demand.There are two conditions which shows this watermark.They are "IsFocused=False" and Length of the Text=0.So we write a MultiTrigger with 2 conditions in it.One is for LostFocus and other is for Text.Length respectively.





<ControlTemplate.Triggers>


    <MultiTrigger>


        <MultiTrigger.Conditions>


            <Condition Property="IsFocused"


                       Value="False" />


            <Condition Property="Text"


                       Value="" />


        </MultiTrigger.Conditions>


        <Setter Property="Visibility"


                TargetName="textBlock"


                Value="Visible" />


    </MultiTrigger>


</ControlTemplate.Triggers>




Now whenever the TextBox comes in a state where the IsFocused=False and Text="" the Watermark TextBlock will get displayed.You can replace the watermark TextBlock by any image or what ever you want..



Complete Style





<Style x:Key="WaterMarkTextBoxStyle"


       BasedOn="{StaticResource {x:Type TextBox}}"


       TargetType="{x:Type TextBox}">


    <Setter Property="Template">


        <Setter.Value>


            <ControlTemplate TargetType="{x:Type TextBox}">


                <Grid>


                    <ScrollViewer x:Name="PART_ContentHost"


                                  SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />


                    <TextBlock x:Name="textBlock"


                               Opacity="0.345"


                               Text="Enter Text Here"


                               TextWrapping="Wrap"


                               Visibility="Hidden" />


                </Grid>


                <ControlTemplate.Triggers>


                    <MultiTrigger>


                        <MultiTrigger.Conditions>


                            <Condition Property="IsFocused"


                                       Value="False" />


                            <Condition Property="Text"


                                       Value="" />


                        </MultiTrigger.Conditions>


                        <Setter Property="Visibility"


                                TargetName="textBlock"


                                Value="Visible" />


                    </MultiTrigger>


                </ControlTemplate.Triggers>


            </ControlTemplate>


        </Setter.Value>


    </Setter>


</Style>





This can be done by a graphics designer alone.That means using Expression Blend.Will be posting steps later.


Wednesday, October 17, 2007

An extented VisualTreeHelper class

Usually if we want to get immediate parent of a Visual(Which considers the elements in Template also) we could use the VisualTreeHelper.GetParent method.This works easy for parent.
But think of getting the children of Visual..Its difficult to call VisualTreeHelper.GetChildren because this needs the index of child.
Here comes the role of this class which wraps these methods and makes its usage simple.

Code

public static class VisualTreeHelperEx
{
public static T FindVisualAncestorByType<T>(DependencyObject dependencyObject) where T : DependencyObject
{
if (dependencyObject == null) return default(T);
if (dependencyObject is T) return (T)dependencyObject;
T parent = default(T);
parent = FindVisualAncestorByType<T>(VisualTreeHelper.GetParent(dependencyObject));
return parent;
}
public static T FindVisualChildByType<T>(DependencyObject dependencyObject) where T : DependencyObject
{
if (dependencyObject == null) return default(T);
if (dependencyObject is T) return (T)dependencyObject;
T child = default(T);
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(dependencyObject); i++)
{
child = FindVisualChildByType<T>(VisualTreeHelper.GetChild(dependencyObject, i));
if (child != null) return child;
}
return null;
}
}

Usage


Window W = VisualTreeHelperEx.FindVisualAncestorByType <Window>(grd);
Rectangle r= VisualTreeHelperEx.FindVisualChildByType<Rectangle>(grd)

Friday, June 29, 2007

Simple grouping in ListBox





<Grid>
<Grid.Resources>
<XmlDataProvider x:Key="Company" XPath="/Company">
<x:XData>
<Company xmlns="">
<Person Name="Jack" Role="CEO"/>
<Person Name="Tim" Role="PL" />
<Person Name="Jil" Role="PL" />
<Person Name="Jimmy" Role="PM" />
<Person Name="Joy" Role="PM" />
<Person Name="Jim" Role="PL" />
<Person Name="Jack" Role="PM" />
</Company>
</x:XData>
</XmlDataProvider>

<DataTemplate x:Key="categoryTemplate">
<TextBlock Text="{Binding Path=Name}" FontWeight="Bold" Background="ForestGreen" Margin="0,5,0,0"/>
</DataTemplate>
<DataTemplate x:Key="template">
<TextBlock Text="{Binding XPath=@Name}"/>
</DataTemplate>

<CollectionViewSource x:Key="cvs" Source="{Binding Source={StaticResource Company},XPath=Person}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="@Role"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</Grid.Resources>


<ListBox Name="lst"
ItemTemplate="{StaticResource template}"
ItemsSource="{Binding Source={StaticResource cvs}}">
<ListBox.GroupStyle>
<GroupStyle HeaderTemplate="{StaticResource categoryTemplate}" />
</ListBox.GroupStyle>
</ListBox>
</Grid>

If you want to sort items in these groups please use SortDescriptions along with GroupDescriptions.For more details visit
http://www.beacosta.com/2006/01/how-do-i-sort-groups-of-data-items.html

Wednesday, June 27, 2007

Extending HeaderedItemsControl to have Footer !!!

The normal HeaderedContentControl in WPF gives us the facility to have a header up on the ItemsControl.This will be enough in most of the cases.But if you are looking for a ItemsControl which needs Footer too this is your solution.


  1. Solution 1

Use the Tag Property to hold Content of Footer.And Template it to have Footer.No inheritance!!!



<HeaderedItemsControl>
<HeaderedItemsControl.Header>Header</HeaderedItemsControl.Header>
<TextBlock Text="Item1" Background="LightGray"/>
<TextBlock Text="Item2" Background="LightGray"/>
<TextBlock Text="Item3" Background="LightGray"/>
<HeaderedItemsControl.Tag>Header</HeaderedItemsControl.Tag>
<HeaderedItemsControl.Template>
<ControlTemplate TargetType="{x:Type HeaderedItemsControl}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height ="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ContentPresenter ContentSource="Header" Grid.Row="0"/>
<ItemsPresenter Grid.Row="1" />
<ContentPresenter ContentSource="Tag" Grid.Row="2"/>
</Grid>
</Border>
</ControlTemplate>
</HeaderedItemsControl.Template>
</HeaderedItemsControl>

Tuesday, May 8, 2007

Target an inner element from setter

Consider a scenario where we need to change the second color of a gradient on mouse over.The normal solution will be as follows.

<Button>
<Button.Template>
<ControlTemplate TargetType="Button">
<Rectangle Width='60' Height='40' x:Name='MyRectangle'>
<Rectangle.Fill>
<LinearGradientBrush >
<GradientStop Color='Red' />
<GradientStop Color='Blue' Offset='1' x:Name='SecondStop' />
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName='MyRectangle' Property="Fill" >
<Setter.Value>
<LinearGradientBrush >
<GradientStop Color='Red' />
<GradientStop Color='Green' Offset='1' />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>

If we folllow this method we need to write the same code twice.If there is a method to change the value of second color directly,it would be more easier to code.The below code does it with the help of binding.


<Button>
<Button.Template>
<ControlTemplate TargetType="Button">
<Rectangle Width='60' Height='40' x:Name='MyRectangle'>

<Rectangle.Tag>
<Color>Blue</Color>
</Rectangle.Tag>

<Rectangle.Fill>
<LinearGradientBrush >
<GradientStop Color='Red' />
<GradientStop Color='{Binding ElementName=MyRectangle, Path=Tag}' Offset='1' x:Name='SecondStop' />
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName='MyRectangle' Property="Tag" Value="Green" >
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>

Friday, April 20, 2007

Get the template of 3rd party controls

If we dont have template of a Control we could get that using Blend.
Load the control in Blend and right click on it then select

Edit Control Parts(Template) -> Edit a Copy

This will create a copy of the template in xaml file.

How can we make a TextBox looks like Button using template?

If we wanna make the Button looks like TextBox it is easy,just add the TextBox as content of Button.But the reverse is not possible sice TextBox doesnt have Content property.So use Templating.

< TextBox Text="Hai" >
< TextBox.Template >
< ControlTemplate >
< Button Content="hai"/ >
< /ControlTemplate >
< /TextBox.Template >
< /TextBox >

CS Code

ControlTemplate ct=new ControlTemplate(typeof(TextBox));
FrameworkElementFactory fef=new FrameworkElementFactory(typeof(Button));
fef.SetValue(Button.ContentProperty,"hai");
ct.VisualTree =fef;
txt.Template = ct;