AvalonControlsLibrary DatePicker refactored

Recently I received some requests from people to support some more styling for the DatePicker control. The initial idea for the DatePicker was to create a “lookless” control and then users would create a ControlTemplate to change the look and feel of the control (which is still 100% possible, see here for more info). Yet sometimes users do not want to totally change the look of the control, sometimes it’s more a matter of changing colors and minor things like that. So I decided to make the DatePicker support some more styling so that users don’t need to create a new ControlTemplate for the DatePicker if they only need to change minor things in the DatePicker UI.

As you can see in the image above I added 5 new properties for styling the control. All of these properties are optional and if they are not set, a default value will be set for you.

DayCellTemplate

This property accepts a DataTemplate where the user can specify how each Day cell should look. The DataTemplate is fed with a DayCell object as DataContext. The DayCell class has the following properties which you can use in the DataTemplate

Property Name Type Description
DayNumber int Represents the Day number
MonthNumber int Represents the Month number
YearNumber int Represents the Year number
IsEnabled bool Flag that indicates if the item falls out of the MinDate and MaxDate range
IsInCurrentMonth bool Flag that indicates if the item is in the current selected month

Here is a sample DataTemplate for the DayCellTemplate.

<DataTemplate>
    <Border Name="border">
        <TextBlock Text="{Binding DayNumber}" Name="dayCell"/>
    </Border>
    <DataTemplate.Triggers>
        <!--This trigger is to do some thing with the template when an item is selected-->
        <DataTrigger Binding="{Binding RelativeSource={
                                RelativeSource AncestorType={x:Type ListBoxItem}},
                                Path=IsSelected}"
                     Value="True">
            <Setter Property="Background" Value="Blue" TargetName="border"/>
        </DataTrigger>
        <!--This is for those dates that fall out of the MinDate and MaxDate.-->
        <DataTrigger Binding="{Binding IsEnabled}" Value="False">
            <Setter Property="Background" Value="Gray" TargetName="border"/>
        </DataTrigger>
        <DataTrigger Binding="{Binding IsInCurrentMonth}" Value="False">
            <Setter Property="Foreground" Value="Gray" TargetName="dayCell"/>
        </DataTrigger>
    </DataTemplate.Triggers>
</DataTemplate>

So basically the DayCellTemplate will give you a lot of flexibility in terms of what you can do with the UI of the DatePicker because you can make the Day cell look however you want without the need of re building the whole UI for the control.

DayHeaderTemplate

The DayHeaderTemplate is again another DataTemplate, this time it will be a DataTemplate for the Header Day cell which basically is the Text -> Sun, Mon, Tue etc.. The DataTemplate that you set as being the DayHeaderTemplate will be passed a string object as DataContext that contains the Text for the Header (ex. Mon, Tue etc..) Here is an example of a DataTemplate that can be applied for the DayHeaderTemplate property.

<DataTemplate>
    <Border Background="Yellow">
        <TextBlock Foreground="Lime" Text="{Binding}"/>
    </Border>
</DataTemplate>

MonthBackButtonStyle/MonthForwardButtonStyle

These two properties are the styles for the back and forward month navigation buttons of the DatePicker. Basically you can apply a style for the Back and Forward button in any way you like. So you may decide even to create a ControlTemplate for these two buttons which would be quite easy. Something like this….

<Style TargetType="Button">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Border BorderBrush="Pink" Width="20" BorderThickness="2">
                    <TextBlock Text="<" FontWeight="Bold"/>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

MonthSelectorStyle

Last but not least is the MonthSelectorStyle property. This property enables you to set a style for the Months drop down list aka ComboBox. Since here we are setting a scyle for a ComboBox a user has full control over that combobox. One can decide to do a ControlTemplate for the ComboBox or maybe just set an ItemTemplate for the elements inside it… Here is a style that I used in the demo app of the DatePicker…

<Style TargetType="ComboBox">
    <Setter Property="Background" Value="Yellow"/>
    <Setter Property="ItemContainerStyle">
        <Setter.Value>
            <Style TargetType="ComboBoxItem">
                <Setter Property="Background" Value="Yellow"/>
            </Style>
        </Setter.Value>
    </Setter>
    <Setter Property="ItemTemplate">
        <Setter.Value>
            <DataTemplate>
                <TextBlock Foreground="Red" Text="{Binding}"/>
            </DataTemplate>
        </Setter.Value>
    </Setter>
</Style>

Conclusion

I think that with the introduction of these properties the DatePicker control will be much more easy to use and re style. Again I would suggest that if you need to totally re arrange the look of this control the best way would be to use a ControlTemplate and change the whole look of the control, yet if all you need is to change some colors and other minor things, these new properties will help you out in the process.

The new version of the DatePicker will be available in the AvalonControlsLibrary v3, yet I know you can’t wait until you get your hands on this so I created a demo app for you 😀

I am open to suggestions as usual! Please let me know if there is something missing or something that you would like to have in YOUR AvalonControlsLibarary DatePicker 🙂

And as my friend Sacha Barber says – “It’s all good!” 😀

Download Demo Project

kick it on DotNetKicks.com

Advertisements

WPF Treeview root node

Unfortunately the WPF native treeview or treeview items do not expose a property to determine which item is the root node in the treeview. I needed such a feature and thought to put it on my blog…

What is a treeview?
Well believe it or not a TreeView is just an Items Control nothing more. Yes, an ItemsControl that creates TreeViewItems as it’s Item Containers. The TreeViewItems are also ItemsControl so a recursive data structure is formed and the TreeViewItems generate there own child nodes.

Today I will not go into details of how the treeview and ItemsControl work… For more info on this visit Dr.Wpf Blog. I will discuss more how I implemented the root nodes for the treeview.

So an ItemsControl has a very special method that one can override to do some custom logic, “PrepareContainerForItemOverride“. The following is the signature of the method

protected override void PrepareContainerForItemOverride(
    DependencyObject element, object item)

Basically this method gets called whenever an item (in our case a TreeViewItem) is being created and decorated with a DataTemplate (if set). In this method we can set a property of the TreeViewItem to identify the item as a root node.Ok, lets start. First we need to sub class the Treeview control. Once we did that we need a way how to attach information to the TreeViewItems… HMMM.. what better could do this then Attached Properties. Once we have all this, we need to set the attached property to True for the root nodes and we are done 🙂 …. something like this

public class MyTreeView : TreeView
    {

        public static bool GetIsRootNode(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsRootNodeProperty);
        }

        public static void SetIsRootNode(DependencyObject obj, bool value)
        {
            obj.SetValue(IsRootNodeProperty, value);
        }

        public static readonly DependencyProperty IsRootNodeProperty =
            DependencyProperty.RegisterAttached("IsRootNode", typeof(bool),
            typeof(MyTreeView), new UIPropertyMetadata(false));

        protected override void PrepareContainerForItemOverride(
            DependencyObject element, object item)
        {
            SetIsRootNode(element, true);
            base.PrepareContainerForItemOverride(element, item);
        }
    }

So the most important part is where we set the Attached property IsRootNode to true (Please also note that by default the Attached property is set to false). You would be wondering, But wouldn’t this make all TreeViewItems root nodes???!!??? And the answer is, NO. Because the Treeview only generate root nodes. all other nodes are generated by the TreeViewItems themselves (Remember that the TreeViewItems are ItemsControl as well :)).

Once we have the property IsRootNode set we can restyle the TreeView as we want by using a Control Template. something like this

<ControlTemplate TargetType="TreeViewItem">
    <StackPanel Margin="10,2,0,0">
        <WrapPanel Name="item">
            <ToggleButton Name="expander"
                          IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, 
                                              Path=IsExpanded}"
                          Content="+"/>
            <ContentPresenter x:Name="PART_Header"
                  ContentSource="Header" />
        </WrapPanel>
        <Border>
            <ItemsPresenter Name="children" Visibility="Collapsed" />
        </Border>
    </StackPanel>
    <ControlTemplate.Triggers>
        <Trigger Property="IsSelected" Value="True">
            <Setter TargetName="item" Property="Background"
                    Value="LightBlue"/>
        </Trigger>
        <Trigger Property="IsExpanded" Value="True">
            <Setter TargetName="children" Property="Visibility"
                    Value="Visible"/>
        </Trigger>
        <Trigger Property="HasItems" Value="False">
            <Setter TargetName="expander" Property="Visibility"
                    Value="Collapsed"/>
        </Trigger>
        <Trigger Property="local:MyTreeView.IsRootNode" Value="True">
            <Setter TargetName="item" Property="Background" Value="Silver"/>
            <Setter TargetName="item" Property="Height"  Value="50"/>
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

The most important part of this ControlTemplate is the Trigger on the attached property local:MyTreeView.IsRootNode.Here we are making the RootNodes for the treeview look different from all other nodes…

Hope this post helps…. Please contact me if you need any help 🙂

Download the full source code

Input Prompt support in WPF

Intro

If you look at Vista User experience guide, one thing that is a must have is the Input Prompt. I think that this is very important to improve the user experience. Yet unfortunately this is not supported natively by WPF 😦

But don’t worry because AvalonControlsLibrary is at the rescue 🙂

I had noting to do today so I decided to create this functionality and share it with you guys… You would say, aha; here comes Marlon with a new control. But NO. This is not a control as such. What I have created is a class with some attached properties that can be used to have the Prompt Input feature for any control (or better any control that would make sense such a feature). I choose the attached properties approach rather than creating a custom control for the simple reason to support any control that you wish to have an input prompt like the one displayed in the image below.

Input prompt

As you can see in the image above I am using the Input Prompt both for the TextBox and the ComboBox. And yes you can use it with any control that you want…

How to use this…

Well using this feature is quite easy, all you have to do is to set an attached property in your control. Something like this…

<TextBox local:InputPrompt.PromptText="Enter Search" />

[where local is the XAML namespace mapping]

In total there are 8 properties that you can set which are

  1. InputPrompt.PromptText – I guess you already figured this one out 😀
  2. InputPrompt.PromptColor – This is a brush used as foreground for the Prompt Text (Default: Gray)
  3. InputPrompt.PromptFontFamily – The font family to use for the Prompt Text (Default: Arial)
  4. InputPrompt.PromptFontSize – The font size of the Prompt Text (Default: 12.0)
  5. InputPrompt.PromptFontStretch – The font stretch to use for the Prompt Text (Default: FontStretches.Normal)
  6. InputPrompt.PromptFontStyle – The font style to use for the Prompt Text (Default: FontStyles.Normal)
  7. InputPrompt.PromptFontWeight – The font weight to use for the Prompt Text (Default: FontWeights.Normal)
  8. InputPrompt.PromptBackColor – This is a brush that is used to color the background of the prompt (Default: Transparent)

Please note: You must set the InputPrompt.PromptText in order for this to work all the other properties are optional. Also you must have you control under an AdornerDecorator because the InputPrompt will draw the prompt text in an adorner.

If you use the Input Prompt with a textbox the input prompt will be much more intelligent. What do I mean by this? Basically the Input Prompt handles the Text Changed event of the TextBox and if the user enters no text the prompt re appears. The same happens if the TextBox looses focus and there is no text in it. I did this behaviour for the TextBox because this is the standard behaviour for an Input Prompt for textboxes.

How does this work behind the scenes

Well it’s quite simple. Basically an Adorner is placed on top of the control which sets the Attached properties and draws the InputPrompt.PromptText. Besides drawing the text this also draws a rectangle covering the surface of the control so that as soon as the user click the control(or better mouse down on the control), the adorner disappears and the control gets activated once again.

When the InputPrompt.PromptText is set for a TextBox, the input prompt will register to the LostFocus event and the TextChanged event and make sure to display the Prompt Text if the Text of the TextBox is to empty.

Conclusion

All this will be included in AvalonControlsLibrary v3 but I decided to upload a demo as a stand alone so that you can start using this immediately.

Hope you like this and as usual I am all ears for feedback and suggestions….

Thanks

Download Source Code and Demo App

kick it on DotNetKicks.com

Support for MinDate and MaxDate in DatePicker and TimePicker

I updated the sources for AvalonControlsLibrary v2 so that to support MinDate and MaxDate in the DatePicker.

Also added support for MinTime and MaxTime in TimePicker.

And while I was at it I also refactored the DateTimePicker to support these 2 properties.

The properties are DependencyProperties so you can easily databind to and do what every you like with them….

Great… now i should go to sleep 😀

Downlaod the new version

AvalonControlsLibrary v2 has been released !

Finally I had some time to release the new version of AvalonControlsLibrary v2.

This release includes

RangeSlider – All properties are now Dependency properties so that you can easily databind with.
RangeSlider – The RangeSelectedChanged event has been refactored into a Routed event.
Range slider – Support for Commands such as MoveBack Move Forward, AllBack and AllForward

DatePicker – Add a DateSelectedChanged routed event – TimePicker – Add a TimeSelectedChanged routed event

DateTimePicker (this will be the DatePicker and TimePicker joined)

DockableContainer (aka Docky- This is a brand new control which supports docking of element and undocking. While elements are un docked you can drag around the element 🙂 Just like Blend Toolbars)

Bug Fixes
Masked TextBox IsReadonly click here for more info
DateTimePicker – setting the date via code before the ControlTemplate being loaded was thowing an exception

Download the new version

Send as much feedback as you can so that I can start working on V3 😀

Thanks for all your support

kick it on DotNetKicks.com

WPF Date Time Picker

[updated 09th Febuary 2008 – Bug fix for DateTimePicker]
After loads of requests for a DateTimePicker in AvalonControlLibrary I finally had sometime to build a DateTimePicker. DateTimePicker is nothing really special it is a DatePicker and a TimePicker combined in one control.

DateTimePicker exposes an important property called DateTimeSelected. DateTimeSelected is a dependency property so that you can use it in data binding. DateTimePicker also exposes an event DateTimeSelectedChanged that is raised whenever the date/time is changed.

There are some other useful properties that you can set to layout this control

MinuteHand – This property takes a Brush and it is used to color the minute hand

HourHand – This property takes a Brush and it is used to color the hour hand

ClockBackground – This property takes a Brush and it is used as Background color for the clock

CalanderHeaderBackground – This property takes a Brush and it is used as Background for the header of the calander

CalanderHeaderForeground – This property takes a Brush and it is used as Foreground for the header text of the calander

This control also supports control templates. You MUST supply a DatePicker named PART_DatePicker and a TimePicker named as PART_TimePicker in order to create a ControlTemplate for this control.

This control will ship in v2 of AvalonControlLibrary. If you have any suggestions or find any bugs please let me know so that I can update it before I release AvalonControlLibrary v2.

Download Demo Project Here

Please note that a new version is available here

DateTimePicker

kick it on DotNetKicks.com

Create Blend like UIs using DOCKY

Docky is a new control for AvalonControlsLibrary. Docky is the codename for this control, the actual name for this control is DockableContainer. Basically Docky is a control that lets you add panels that can be dockable. By Dockable I mean that you can specify where the child panel (control) needs to be docked. If you un dock one of the panels then the panel can be dragged any where on screen (within the working area)

Docky

Using Docky is very similar as using a dockpanel. Like a DockPanel, Docky has an attached property called Dock which you can use to specifiy where you want your panel to be docked. If you do not specify this property Docky will dock your control in the middle ( this is a behavior like Fill). An example for using the Dock property is

< Grid local:DockableContianer.Dock=”Left” ……

Another important thing to know about Docky is how you can make your control be able to Dock and UnDock. Basically there is a command called ToggleDockChild that you can use to Dock and undock your control. This command needs a Parameter which is a reference to the control that is docked. So for example if the panel that is docked is a grid and inside it I have a button that dock and undocks the grid, I would have to pass the instance of the grid as parameter. Let me give an example

<Grid>
<Button Command=”{local:DockableContainer.ToggleDockChild}” CommandParameter=”{Binding RealtiveSource={RelativeSource AncestorType={x;Type Grid}} }”/>
</Grid>

The last thing that one has to do in order to use this control is set the ElementForDragging attached property. This property is used to let the DockableContainer know which control will be used to drag the panel when it is UnDocked. The value of this property should be set as the Panel to drag. You can put this property in any child element of the element being docked because the Docky will analyze the ViusalTree of children of the docked element and check which child has this property set. This is a useful feature for when you need to be able to drag the panel from the Middle part or bottom etc… Again I will give an example

<Grid>
<Button Command=”{local:DockableContainer.ToggleDockChild}” CommandParameter=”{Binding RealtiveSource={RelativeSource AncestorType={x;Type Grid}} }”/>

<Border local:DockableContainer.ElementForDragging=”{Binding RealtiveSource={RelativeSource AncestorType={x;Type Grid}} }“/>
</Grid>

So here what we are saying is that the surface where the user can grab to drag the panel is the Border.

Ok so there is some work to do in order to use this control, so I decided to create a control that handles all this stuff for you. The control is called DockableControl and it inherites from HeaderedContentControl. This control handles all attached properties and commands for the DockableContainer so all you have to do, is to feed the Header and the Content and all the other stuff is catered for.

I created a Demo Project for this control so that you do not need to download AvalonControlsLibrary (well in actual fact I didn’t commit the changes to codeplex yet since I am still doing some refactoring 🙂 ). Download the code for this control and see how it works to get a better idea of how one can use this control…..

If you have any problems, questions or bugs feel free to send me an email at marlongrech@gmail.com or post a comment to this post 🙂

Hope you like it …

DOWNLOAD DEMO PROJECT

Regards