Click here to Skip to main content
6,935,596 members and growing! (14,686 online)
Email Password   helpLost your password?
General Programming » Date and Time » General     Intermediate License: The Microsoft Public License (Ms-PL)

PersianDate and some WPF controls for it

By Arash Sahebolamri

The code represents a type for holding Persian date values, and two WPF controls for working with Persian dates.
C#3.0, Windows, .NET3.0, XAML, WPF, Dev
Revision:5 (See All)
Posted:4 Nov 2009
Updated:12 Nov 2009
Views:3,059
Bookmarked:7 times
printPrint Friendly   add Share
      Discuss Discuss   Broken Article?Report  
7 votes for this article.
Popularity: 3.55 Rating: 4.20 out of 5

1

2
1 vote, 14.3%
3
2 votes, 28.6%
4
4 votes, 57.1%
5

PersianDateAndWpfDemo

Introduction

The source code consists of three projects: PersianDate, which is a type (structure actually) for holding values of the Persian calendar; PersianDateControls, which has two WPF controls for Persian calendar: PersianCalendar and PersianDatePicker (these controls are pretty much like the ones found in the WPF Toolkit: Calendar and DatePicker; these two controls use the type PersianDate to work with values of the Persian calendar); and the third project is a simple demo that demonstrates using these controls.

About the Persian Calendar

The Persian calendar is a sonar calendar, like Gregorian calendar, but there are some differences. One is that the origins are different, and the Persian calendar's origin is about 621 years after Gregorian calendar's; another one is that Persian calendar's first day of year is March 21; and probably the most important one is that the average length of a Persian calendar year is different from that of a Gregorian calendar's: the Persian calendar has 8 leap years (that is a year that has an extra day than normal years) in each 33 years, whereas the Gregorian calendar has 8 leap years in each 32 years. This little difference means that Persian dates cannot be calculated directly from Gregorian dates.

The PersianDate Structure

The PersianDate structure stores dates of the Persian calendar. It is somehow similar to the DateTime structure in the .NET Framework Class Library, except that PersianDate only stores the date, and it doesn't store the time. This structure has only one field, which stores the number of days passed after the first day of the first year of the Persian calendar(1/1/1):

uint n; //the only field, stores the number of days passed 1/1/1 

The calculations for the year, month, and day are based on this single value. The private yearMonthDay() method takes this number and returns the day, month, and year represented by this number. In order to do so, dates are divided into some groups:

const int period33y = 365 * 33 + 8;

const int p33p1 = 366;
const int p33p2 = 365 * 20 + 4;
const int p33p3 = 366;
const int p33p4 = 365 * 11 + 2;

The first constant (period33y) is the number of days in each 33 years; this is divided into four groups: in each one, the number of days in a year are the same. For example, if n % period33y is 400, these categories mean that the date is in the p33p2 group since it is > p33p1 and <= p33p1+p33p2, and that means that the date is not in a leap year, and by doing some relatively simple calculations, the year of the date can be extracted. After that, the day and month parts of the date are extracted in this method.

These constants are also used when calculating n from the year, month, and day. The days() method does this. This method is used in one of the constructors of the structure which takes the year, month, and day as arguments.

Some Notable Points About PersianDate

The PersianDate is a structure, not a class, because of performance reasons. As mentioned before, this structure has only one 4 byte field, so it is much more rational to make it a structure than a class. Since access to objects of classes are indirect, and a reference to an object is at least 4 bytes long, which is the size of the data itself, it doesn't seem reasonable to make this type a reference type.

The type is immutable, and this is the recommended way of making structures. The reason is that mutable structures have weird behaviours in certain scenarios. For example, suppose that the type was mutable, and there was an AddDays() method which would add the number of days given as the parameter to the instance. Now suppose that there is a Foo class which has a field of type PersianDate named DateField:

Foo foo=new Foo();
foo.DateField=new PersianDate(1376,2,22);
foo.DateField.AddDays(12);
System.Console.WriteLine(foo.dateField.ToString());

The output would be 1376/3/2, which is what you might have expected. Now, suppose that this Foo class also had a property of type PersianDate, named dateProperty, and let's say it was auto implemented:

class Foo{
    public PersianDate DateProperty{get; set;}
    ...
}

If you wrote a similar code to the one you had written for DateField:

Foo foo=new Foo();
foo.DateProperty=new PersianDate(1376,2,22);
foo.DateProperty.AddDays(12);
System.Console.WriteLine(foo.dateProperty.ToString());

the output would be 1376/2/22! The reason is that since PersianDate is a value type, the getter of dateProperty would return a copy of the value stored, and the AddDays method would mutate this copy, and not the actual backing field; and that is why the value of the property is not changed.

So that is why PersianDate is immutable.

The PersianCalendar Class

PersianCalendar is a WPF user control. In WPF, user controls derive from the System.Windows.Controls.UserControl base class. This WPF control represents the Persian calendar, very much like the Calendar control (System.Windows.Controls.Calendar) in the WPF Toolkit. Just like WPF's Calendar, it has a property called DisplayMode which can be used to choose how the calendar is displayed: whether it displays years in a decade, months in a year, or days in a month.

This control uses the PersianDate type to work with the Persian calendar, so properties like DisplayDate or SelectedDate are of this type.

Some stuff about the PersianCalendar class: I have used WPF's UniformGrid control as the container control to arrange the date buttons in PersianCalendar:

<UniformGrid Margin="3,26,3,2" Name="monthUniformGrid" 
  Rows="7" Columns="7"  FlowDirection="RightToLeft"/>
<UniformGrid Margin="3,26,3,2" Name="yearUniformGrid" 
  Columns="3" Rows="4" FlowDirection="RightToLeft"/>
<UniformGrid Margin="3,26,3,2" Name="decadeUniformGrid" 
  Columns="3" Rows="4" FlowDirection="RightToLeft"/>

Each one is used for one of DisplayMode's three values. For example, when the DisplayMode is set to Month, monthUniformGrid is displayed and the other two are collapsed (that is, they are hidden and they don't reserve space):

private void setMonthMode()
{
    this.decadeUniformGrid.Visibility = 
      this.yearUniformGrid.Visibility = Visibility.Collapsed;
    this.monthUniformGrid.Visibility = Visibility.Visible;
    ...
}

Customizing the Appearance of Controls Using Styles and Templates

In order for the PersianCalendar to work, these UniformGrids must be filled with controls that display dates (or months or decades). Label is not a good choice because it doesn't have a Click event, so I have used Button; but Button's appearance didn't seem very pleasing for this purpose, so I have used Styles and Templates to change it:

<Style x:Key="InsideButtonsStyle" TargetType="Button">
    ...
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Border x:Name="Border" CornerRadius="2" 
                         BorderThickness="0" 
                         Background="{TemplateBinding Background}" 
                         BorderBrush="{StaticResource NormalBorderBrush}">
                    <ContentPresenter Margin="2" 
                       HorizontalAlignment="Center" 
                       VerticalAlignment="Center" 
                       RecognizesAccessKey="True"/>
                </Border>
                <ControlTemplate.Triggers>
                    ...
                    <Trigger Property="IsMouseOver" Value="true">
                        <Setter TargetName="Border" 
                            Property="Background" 
                            Value="{StaticResource HoverBackgroundBrush}" />
                        <Setter  Property="Foreground" 
                            Value="{StaticResource HoverForegroundBrush}" />
                    </Trigger>
                    <Trigger Property="IsMouseOver" Value="false">
                        <Setter  Property="Foreground" 
                           Value="{StaticResource HoverForegroundBrush}" />
                    </Trigger>
                    ...
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Inside the ControlTemplate, Triggers are used to alter the appearance of the buttons when, for example, they are hovered by the mouse, etc.

Something interesting about this template is the use of Template Binding to bind the value of the Button's Background property to the Background property of the template's visual tree element, Border.

This style, along with the template defined in it, is applied to buttons when they are created:

Button newControl()
{
    var element = new Button
    {
        ...
        Style = (Style)this.FindResource("InsideButtonsStyle"),
        ...
    };
    return element;
}

Dependency Properties and Routed Events

All the properties defined in the PersianCalendar class are Dependency Properties, and the events are RoutedEvents; this is WPF's recommended style for making user controls. Making the properties dependency properties requires that no extra code be put in their getter and setter accessors, so PropertyMetaData is used whenever any validation or mutation of the PersianCalendar object is required. For example, consider the SelectedDate property:

public PersianDate SelectedDate
{
    get { return (PersianDate)GetValue(SelectedDateProperty); }
    set { SetValue(SelectedDateProperty, value); }
}               
public static readonly DependencyProperty SelectedDateProperty;

As you can see, all the setter does is just set the value for the backing field, which is of type DependencyProperty, of course. The extra logic is put into the property's metadata (by using lambda expressions in my code) in the static constructor of the class:

static PersianCalendar()
{
    ...
    PropertyMetadata selectedDateMetaData = new PropertyMetadata(
    (DependencyObject d, DependencyPropertyChangedEventArgs e) =>
    {
        PersianCalendar pc = d as PersianCalendar;
        pc.selectedDateCheck((PersianDate)e.OldValue);
    }
    );
    SelectedDateProperty=
        DependencyProperty.Register("SelectedDate", 
          typeof(PersianDate), typeof(PersianCalendar), selectedDateMetaData);
    ...
}

The PersianDatePicker Class

It doesn't do any magic really. This control just uses a TextBox and a PersianCalendar, and holds the PersianCalendar in a Popup control to display it in a different window whenever the corresponding button is clicked. There is one thing notable about this class though, and that is using Data Binding for connecting the properties of this class to those of the PersianCalendar. Here is the code that demonstrates using this feature for binding the SelectedDate property:

Binding selectedDateBinding = new Binding
{
    Source = this.persianCalendar,
    Path = new PropertyPath("SelectedDate"),
    Mode = BindingMode.TwoWay,
};
this.SetBinding(SelectedDateProperty, selectedDateBinding);

Using this technique has relieved me from having to write all the messy code to keep these properties in sync.

How to Use the Code

If you just want to use PersianDate, you can either add its project to your solution, or build it and reference the assembly; and if you want to use the WPF controls, you should either add both projects (PersianDate and PersianDateControls) to your solution, or build them both and reference them both (since PersianDateControls uses PersianDate).

History

  • Ver. 1.1:
  • Removed PersianDateControl's dependency on the WPFToolkit assembly (actually, it only used the CalendarMode enum from that assembly, which is now in the CalendarMode.cs code file in the project), plus some other minor changes (note that you still need WPFToolkit if you want to build and run the demo project).

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)

About the Author

Arash Sahebolamri


Member

Location: Iran (Islamic Republic Of) Iran (Islamic Republic Of)

Other popular Date and Time articles:

 
Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 4 of 4 (Total in Forum: 4) (Refresh)FirstPrevNext
GeneralGood Job PinmemberDr TJ13:31 22 Dec '09  
Generalany win form version? PinmemberAli Poostchian19:47 9 Nov '09  
GeneralRe: any win form version? PinmemberArash Sahebolamri10:25 11 Nov '09  
GeneralRe: any win form version? PinmemberHamid Reza Mohammadi20:33 13 Nov '09  
For windows for version, take a look at this article:
Farsi Library - Working with Dates, Calendars, and DatePickers[^]

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+PgUp/PgDown to switch pages.

PermaLink | Privacy | Terms of Use
Last Updated: 12 Nov 2009
Editor: Smitha Vijayan
Copyright 2009 by Arash Sahebolamri
Everything else Copyright © CodeProject, 1999-2010
Web20 | Advertise on the Code Project