Styling the WPF Calendar to Resemble Outlook's Month View Calendar

By Michael Detras

This article shows how to style the WPF calendar to resemble Microsoft Outlook Calendar in Month view and how to add appointments.

Introduction

I was in search for a calendar where appointments can be added. I've seen a great CodeProject article by kirkaiya where he achieved this by creating a UserControl. It's very good but I thought I could achieve almost the same thing by styling the WPF Calendar. Figure 1 shows the WPF calendar.


Figure 1. WPF Calendar in its Default Style

My first impression is that it might not be possible. Anyway, I wanted to give it shot. I came across another article at MSDN Magazine, this time by Charles Petzold. He explained in great detail the different parts of the Calendar's template. After reading the article, it seems to me that it is not enough to change the Calendar's template. A custom control that inherits from Calendar should be created to support appointments.

Getting Started

The best way to style a WPF control is to start from the default style. Fortunately, we don't need any tools to get the default style. The source code is freely available at CodePlex, so I recommend downloading it first. Upon extracting the zip file, you can get the Calendar's default style from WPFToolkitBinariesAndSource\Toolkit-release\Calendar\Themes\Generic.xaml. This file has a resource dictionary containing 4 styles for the following controls: Calendar, CalendarItem, CalendarDayButton and CalendarButton.

The Calendar's control template only consists of a CalendarItem control inside a StackPanel. This means that the default appearance of the Calendar is mostly defined by the CalendarItem's control template. However, you can still add other controls to the Calendar's template.

The CalendarItem control is basically divided into the following parts: previous button, next button, header button, month content grid, and year content grid. The appearance of the CalendarItem depends on the selected display mode: month, year or decade.

The month content grid is used when the display mode is month while the year content grid is used for the other two display modes. The CalendarItem fills up the month content grid with CalendarDayButton controls. Meanwhile, the year content grid is filled up with CalendarButton controls. Since we are only interested in the month view of the calendar, we don't need to edit the CalendarButton template.

Let's create a WPF application that shows a calendar in the main window. Copy the default styles for Calendar, CalendarItem and CalendarDayButton controls in the window's resources and add the required assemblies and namespaces. If you are using Visual Studio 2008 and .NET 3.5 SP1, you might get the following error: "The attachable property 'VisualStateGroups' was not found in type 'VisualStateManager'. This is a known bug and you won't be able to see the Calendar in the WPF designer. However, the application should be able to run without any errors.

Resizing the Calendar

The Calendar should fill the entire grid and resized when the main window is resized. This can't be done just by setting the width and height of the Calendar. First, let's change the Calendar's control template. I changed the StackPanel into a Grid and removed the HorizontalAlignment.

<Grid Name="PART_Root">
<primitives:CalendarItem
Name="PART_CalendarItem"
Style="{TemplateBinding CalendarItemStyle}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
/>
</Grid>

Listing 1. Calendar Control Template

Although the CalendarItem fills the grid, the CalendarItem's content (the navigation buttons, header button and month content grid) is aligned to the top left corner of the grid. So we need to edit the CalendarItem's template so that the content is distributed evenly. But first, we should give a key to the CalendarItem style and use it as the value of the Calendar's CalendarItemStyle property. After that, look for the grid that has 2 rows and 3 columns in the CalendarItem's control template. The first row contains the navigation and header buttons. The second row contains the month content grid. The first column contains the previous button, second column contains the header button and third column contains the next column. The month content grid spans 3 columns. Let's add another column that will occupy the remaining space. The month content grid will now span 4 columns.

We should also change the row and column definitions of the month content grid. This grid contains 7 rows and 7 columns, where the Height and Width properties are set to Auto. The first row corresponds to the day title (Su, Mo, Tu, etc.) while the other 6 rows contain the days of the month (1, 2, 3 and so on). The 7 columns correspond to the 7 days of the week. Let's set the Height of the last 6 rows and the Width of all columns to *. These changes result in the following figure.


Figure 2. Resized Calendar

Styling the Navigation and Header Buttons

The navigation buttons in Outlook are displayed as arrows inside circles. The displayed month is also not in the middle of the navigation buttons, but located at the right. The font properties are also a bit different. Let's start first with the circle background of the navigation buttons.

<Style x:Key="NavigationEllipseStyle" TargetType="{x:Type Ellipse}">
<Setter Property="Width" Value="20"/>
<Setter Property="Height" Value="20"/>
<Setter Property="Stroke" Value="#FF8EB0DC"/>
<Setter Property="StrokeThickness" Value="1"/>
<Setter Property="Fill">
<Setter.Value>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#FFFAFCFF" Offset="0"/>
<GradientStop Color="#FFFAFCFF" Offset="0.5"/>
<GradientStop Color="#FFCCE2FF" Offset="0.5"/>
<GradientStop Color="#FFCCE2FF" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>

Listing 2. The Navigation Button's Ellipse

I added this style in the resources section of the grid containing the navigation buttons. The following code shows the inner grid of the updated previous button template which uses the style shown in Listing 2. The path objects that make up the arrow and other properties like margin and width are also updated.

<Grid>
<Ellipse Style="{StaticResource NavigationEllipseStyle}"/>
<Path Margin="4,0,0,0" Height="10" Width="6" VerticalAlignment="Center" HorizontalAlignment="Left" Stretch="Fill" Data="M288.75,232.25 L283,236.625 L288.75,240.625" StrokeThickness="2">
<Path.Stroke>
<SolidColorBrush x:Name="TextColor" Color="#FF406CA6" />
</Path.Stroke>
</Path>
<Path Margin="4,0,0,0" Height="10" Width="12" VerticalAlignment="Center" HorizontalAlignment="Left" Stretch="Fill" Data="M283,236.625 L297,236.625" Stroke="#FF406CA6" StrokeThickness="2"/>
</Grid>

Listing 3. Part of Updated Previous Button Template

In the following code, I added a margin around the previous button and set its width to 20 instead. I just applied the same thing with the next button, with the arrow's paths reversed.

<Button x:Name="PART_PreviousButton"
Margin="4"
Grid.Row="0" Grid.Column="0"
Template="{StaticResource PreviousButtonTemplate}"
Height="20" Width="20"
HorizontalAlignment="Left"
Focusable="False"
/>

Listing 4. Updated Previous Button

Finally, I changed the font weight and size properties of the header button. Also notice that the header and next buttons have switched places.

<Button x:Name="PART_HeaderButton"
Grid.Row="0" Grid.Column="2"
Template="{StaticResource HeaderButtonTemplate}"
HorizontalAlignment="Center" VerticalAlignment="Center"
FontWeight="Normal" FontSize="20"
Focusable="False"
/>

Listing 5. Updated Header Button

The following figure shows the updated Calendar.


Figure 3. Updated Navigation and Header Buttons

Changing the Day Title Format

As you see, the format of each day title is set to the shortest day name like Su for Sunday, Mo for Monday, and so on. Unfortunately, the Calendar or the CalendarItem does not expose any property that let's us change the day title format easily. The CalendarItem uses only the ShortestDayNames property of the current date format. However, we can still change the format by using an IValueConverter as you will see later. The following code shows the updated DayTitleTemplate.

<local:DayNameConverter x:Key="DayNameConverter"/>

<!-- Start: Data template for header button -->
<DataTemplate x:Key="DayTitleTemplate">
<Grid>
<TextBlock
FontWeight="Normal"
FontFamily="Arial"
FontSize="10.5"
Foreground="#FF7C93D7"
HorizontalAlignment="Center"
Text="{Binding Converter={StaticResource DayNameConverter}}"
Margin="0,6,0,6"
VerticalAlignment="Center"/>
</Grid>
</DataTemplate>

Listing 6. Updated Day Title Template

The Text property of the TextBlock is bound to a string representing the shortest day name. So if we want to change Su to Sunday, Mo to Monday and so on, we need to use an IValueConverter, like the one shown below.

/// <summary>
/// Converts the specified short day name to its normal counterpart.
/// </summary>
[ValueConversion(typeof(string), typeof(string))]
public class DayNameConverter : IValueConverter
{
object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
DateTimeFormatInfo dateTimeFormat = GetCurrentDateFormat();
string[] shortestDayNames = dateTimeFormat.ShortestDayNames;
string[] dayNames = dateTimeFormat.DayNames;

for
(int i = 0; i < shortestDayNames.Count(); i++)
{
if (shortestDayNames[i] == value.ToString())
{
return dayNames[i];
}
}

return
null;
}

object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}

private
static DateTimeFormatInfo GetCurrentDateFormat()
{
if (CultureInfo.CurrentCulture.Calendar is GregorianCalendar)
{
return CultureInfo.CurrentCulture.DateTimeFormat;
}

foreach (Calendar cal in CultureInfo.CurrentCulture.OptionalCalendars)
{
if (cal is GregorianCalendar)
{
DateTimeFormatInfo dtfi = new CultureInfo(CultureInfo.CurrentCulture.Name).DateTimeFormat;
dtfi.Calendar = cal;
return dtfi;
}
}

DateTimeFormatInfo
dt = new CultureInfo(CultureInfo.InvariantCulture.Name).DateTimeFormat;
dt.Calendar = new GregorianCalendar();

return
dt;
}
}

Listing 7. Day Name Converter

This IValueConverter converts the shortest day name to its normal day name equivalent. The Convert method uses the GetCurrentDateFormat method in getting the current date format. This is the same method used by the CalendarItem in generating the day titles. The following figure shows the updated Calendar. Notice that I also changed the text color.


Figure 4. Updated Day Titles

Styling the CalendarDayButton

In Outlook, the days are located on the top left corner of each cell. Also, there is a filled rectangle on top of each cell. To imitate this in our Calendar, we'll need to update the CalendarDayButton template. The following XAML code is a part of the updated CalendarDayButton control template.

<Rectangle x:Name="SelectedBackground" Grid.Row="1" RadiusX="1" RadiusY="1" Opacity="0" Fill="{TemplateBinding Background}"/>
<Rectangle x:Name="Background" Grid.Row="1" RadiusX="1" RadiusY="1" Opacity="0" Fill="{TemplateBinding Background}" />
<Rectangle x:Name="InactiveBackground" Grid.Row="1" RadiusX="1" RadiusY="1" Opacity="0" Fill="#FFA5BFE1"/>
<Border>
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop x:Name="StartGradient" Color="#FFDFE8F5" Offset="0"/>
<GradientStop Color="{Binding ElementName=StartGradient, Path=Color}" Offset="0.5"/>
<GradientStop x:Name="EndGradient" Color="#FFC9D9ED" Offset="0.5"/>
<GradientStop Color="{Binding ElementName=EndGradient, Path=Color}" Offset="1"/>
</LinearGradientBrush>
</Border.Background>
<ContentPresenter
x:Name="NormalText"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Margin="5,1,5,1">
<TextElement.Foreground>
<SolidColorBrush x:Name="selectedText" Color="#FF333333"/>
</TextElement.Foreground>
</ContentPresenter>
</Border>
<Rectangle x:Name="Border" StrokeThickness="0.5" Grid.RowSpan="2" SnapsToDevicePixels="True">
<Rectangle.Stroke>
<SolidColorBrush x:Name="BorderBrush" Color="#FF5D8CC9"/>
</Rectangle.Stroke>
</Rectangle>
<Path x:Name="Blackout" Grid.Row="1" Opacity="0" Margin="3" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" RenderTransformOrigin="0.5,0.5" Fill="#FF000000" Stretch="Fill" Data="M8.1772461,11.029181 L10.433105,11.029181 L11.700684,12.801641 L12.973633,11.029181 L15.191895,11.029181 L12.844727,13.999395 L15.21875,17.060919 L12.962891,17.060919 L11.673828,15.256231 L10.352539,17.060919 L8.1396484,17.060919 L10.519043,14.042364 z"/>
<Rectangle Width="0" x:Name="DayButtonFocusVisual" Grid.Row="1" Visibility="Collapsed" IsHitTestVisible="false" RadiusX="1" RadiusY="1" Stroke="#FF45D6FA"/>

Listing 8. Part of Updated CalendarDayButton Template

If you look at the default style, there is a Rectangle labeled TodayBackground. You can see this as the gray background of the grid containing the current day. I've removed this since Outlook indicates the current day differently. I've also added another row so that the first row contains the day and has a blue background (this is the LinearGradientBrush in the above XAML) while the second row has a white background and will show the appointments for that day. More on that later.

When the current VisualState is set to Today, the following animations take place. Basically, it changes the background color of the rectangle containing the day and the border's color and stroke thickness.

<vsm:VisualState x:Name="Today">
<Storyboard>
<ColorAnimation Duration="0" Storyboard.TargetName="StartGradient" Storyboard.TargetProperty="Color" To="#FFF7D275"></ColorAnimation>
<ColorAnimation Duration="0" Storyboard.TargetName="EndGradient" Storyboard.TargetProperty="Color" To="#FFF3B84B"></ColorAnimation>
<ColorAnimation Duration="0" Storyboard.TargetName="BorderBrush" Storyboard.TargetProperty="Color" To="#FFF3B84B"></ColorAnimation>
<DoubleAnimation Duration="0" Storyboard.TargetName="Border" Storyboard.TargetProperty="StrokeThickness" To="2"></DoubleAnimation>
</Storyboard>
</vsm:VisualState>

Listing 9. StoryBoard when VisualState is Today

I've also added a rectangle and named it InactiveBackground. Its opacity is set to 1 when the VisualState is Inactive. You can see this background for days that are shown on the calendar but is not included in the currently displayed month. For example, Oct. 31 is shown but is inactive when the current month displayed is November.

<vsm:VisualState x:Name="Inactive">
<Storyboard>
<ColorAnimation Duration="0" Storyboard.TargetName="selectedText" Storyboard.TargetProperty="Color" To="#FF777777"></ColorAnimation>
<DoubleAnimation Duration="0" Storyboard.TargetName="InactiveBackground" Storyboard.TargetProperty="Opacity" To="1"></DoubleAnimation>
</Storyboard>
</vsm:VisualState>

Listing 10. StoryBoard when VisualState is Inactive

The following figure shows the updated Calendar.



Figure 5. Styled CalendarDayButton

Finalizing the Style

There are some minor things that still need to be done, like setting the margins, borders, background etc. The most noticeable is the light-blue background at the top of the Calendar. The background's height resizes proportionally with the height of the window. This is not the behavior we want. We can remove this by not specifying the background of the CalendarItem in the Calendar’s control template. The following figure shows the final Calendar after applying or updating some margins and adding background to some grid rows.


Figure 6. Final Calendar Style

Adding Appointments

To add appointments, we need to create a custom control that will inherit from the Calendar control. This will mean that we should move the style definitions from the window’s resources section into the custom control’s resource dictionary. This custom control, shown in the code below, will have a variable that will contain the list of appointments.

/// <summary>
/// Custom calendar control that supports appointments.
/// </summary>
public class MonthViewCalendar : Calendar
{
public static DependencyProperty AppointmentsProperty =
DependencyProperty.Register
(
"Appointments",
typeof(ObservableCollection<Appointment>),
typeof(Calendar)
);

///
<summary>
/// The list of appointments. This is a dependency property.
/// </summary>
public ObservableCollection<Appointment> Appointments
{
get { return (ObservableCollection<Appointment>)GetValue(AppointmentsProperty); } set { SetValue(AppointmentsProperty, value); }
}

static
MonthViewCalendar()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MonthViewCalendar), new FrameworkPropertyMetadata(typeof(MonthViewCalendar)));
}

public
MonthViewCalendar()
: base()
{
SetValue(AppointmentsProperty, new ObservableCollection<Appointment>());
}
}

Listing 11. Custom Calendar Control

The Appointments collection accepts objects of type Appointment, which is shown below.

/// <summary>
/// The appointment data.
/// </summary>
public class Appointment
{
public string Subject { get; set; }

public
DateTime Date { get; set; }
}

Listing 12. Appointment Class

This class contains only a few details. I won’t imitate Outlook’s implementation of adding appointments. In this implementation, when a user double-clicks on a CalendarDayButton, the appointment dialog will be shown. The following figure shows the appointment dialog.


Figure 7. Appointment Dialog

My first idea was to derive from CalendarDayButton. But it impossible as the CalendarDayButton is a sealed class. After reading Charles Petzold’s article I mentioned in the Introduction, my only choice is to override the OnMouseDoubleClick method of the Calendar class. The following shows the overridden method.

protected override void OnMouseDoubleClick(MouseButtonEventArgs e)
{
base.OnMouseDoubleClick(e);

FrameworkElement
element = e.OriginalSource as FrameworkElement;

if
(element.DataContext is DateTime)
{
AppointmentWindow appointmentWindow = new AppointmentWindow
(
(Appointment appointment) =>
{
Appointments.Add(appointment);
}
);

appointmentWindow.Show();
}
}

Listing 13. The OnMouseDoubleClick Method

The tricky part is how we will know if the user really clicked a CalendarDayButton. The OriginalSource property of the MouseButtonEventArgs object will not return an object of type CalendarDayButton. It might return any object in the CalendarDayButton’s control template, like rectangle or path. Fortunately, the DataContext value of the CalendarDayButton is inherited by controls deeper in the visual tree. Thus, if the DataContext property is of type DateTime, we know that the user clicked on a CalendarDayButton.

The next thing to do is display the appointments. This can be achieved by updating the CalendarDayButton control template. The basic idea is to add a ListBox where its ItemsSource property is bound to the Appointments property of the MonthViewCalendar control. We also need to filter the appointments based on the date of the CalendarDayButton. I used an IMultiValueConverter for this purpose. The following XAML code is a part of the updated CalendarDayButton template.

<!-- Appointments -->

<ListBox
x:Name="appointmentsLbx"
Grid.Row="1"
Background="Transparent"
BorderBrush="Transparent"
HorizontalContentAlignment="Stretch"
>
<ListBox.ItemsSource>
<MultiBinding Converter="{StaticResource AppointmentsConverter}">
<Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type local:MonthViewCalendar}}" Path="Appointments"/>
<Binding RelativeSource="{RelativeSource Mode=Self}" Path="DataContext"/>
</MultiBinding>
</ListBox.ItemsSource>
<ListBox.ItemTemplate>
<DataTemplate>
<Border Background="#FFDFE8F5" BorderBrush="#FF5D8CC9" BorderThickness="1" CornerRadius="4">
<TextBlock HorizontalAlignment="Center" Text="{Binding Subject}"/>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
<ControlTemplate.Triggers>
<Trigger SourceName="appointmentsLbx" Property="HasItems" Value="False">
<Setter TargetName="appointmentsLbx" Property="Visibility" Value="Hidden"/>
</Trigger>
</ControlTemplate.Triggers>

Listing 14. CalendarDayButton’s Appointments ListBox

I used multi-binding to filter the appointments based on the date on the CalendarDayButton. This is because we need to pass 2 objects to the IMultiValueConverter: the appointments collection and the date. The following shows the IMultiValueConverter code.

/// <summary>
/// Gets the appointments for the specified date.
/// </summary>
[ValueConversion(typeof(ObservableCollection<Appointment>), typeof(ObservableCollection<Appointment>))]
public class AppointmentsConverter : IMultiValueConverter
{
#region IMultiValueConverter Members

public
object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
DateTime date = (DateTime)values[1];

ObservableCollection
<Appointment> appointments = new ObservableCollection<Appointment>();
foreach (Appointment appointment in (ObservableCollection<Appointment>)values[0])
{
if (appointment.Date.Date == date)
{
appointments.Add(appointment);
}
}

return
appointments;
}

public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}

#endregion
}

Listing 15. Appointments Converter

Everything should work now except for 1 minor glitch. The list box’s items do not get updated immediately after adding an appointment to the collection. This can be fixed by implementing the INotifyPropertyChanged interface on the MonthViewCalendar class and raising the PropertyChanged event when an appointment is added. The following figure shows the calendar with some appointments.


Figure 9. Calendar with Appointments

The Visual Studio 2008 solution can be downloaded here. Note that I haven’t implemented updating an appointment.

Popularity  (21700 Views)
Biography - Michael Detras
.NET developer. Interested in WPF, Silverlight, and XNA.
My blog
My FAQs
Create New Account
Article Discussion: Styling the WPF Calendar to Resemble Outlook's Month View Calendar
Michael Detras posted at Wednesday, November 04, 2009 9:09 AM
reply
Tram replied to Michael Detras at Friday, June 10, 2011 5:07 PM
Hi,
I'm very interested in your topics, i'm designing a Calendar like yours, but in windows application, not in web application.
And I don't know how to do, can you show me the way to do.
Thank you so much.
I'm looking forward your answer.
Best regards.
reply
The calendar is for a WPF application.
Michael Detras replied to Tram at Friday, June 10, 2011 5:07 PM
Hi Tram,

The Calendar control here is for a WPF application, which is also a kind of a Windows application. If you are developing a Windows Forms application, then I think you could host the WPF control.

Best regards,
Mike
reply
jenn replied to Michael Detras at Friday, June 10, 2011 5:07 PM
Just wanted to start off by saying what a well put together post this was :)

my question is this:

1. is there a direct link to this download you speak of at code?
and do i need it..
i cant find the download your speaking of.

2. i have started a project in studio.net...using vb.net as the language..am i gonna add this on as a form...and will it have any impact with the current project. if so is there a way to fix it?

i am very new at this, only been at it for a few weeks, so dont really understand the ropes just yet...thank you for your post..it is just what i am trying to accomplish :)
reply
WPF Toolkit
Michael Detras replied to jenn at Friday, June 10, 2011 5:07 PM
Thanks for reading the article. Ok, I forgot to mention where to download the WPF calender. It is found in the WPF toolkit, which you can download in this link http://wpf.codeplex.com/releases/view/40535. I haven't check it yet but it may be included already in VS 2020 and .NET 4. If that's the case, you don't need to install it.

I've done this in C# so you need to convert it to VB. I think there are tools out there that you can use to convert C# to VB. You can check Pete O'Hanlon's MoXaml PowerToys http://peteohanlon.wordpress.com/moxaml-power-toys/ and see if it works for you.

Cheers!
reply
jenn replied to Michael Detras at Friday, June 10, 2011 5:07 PM
okay...:)

thank you..i went and downloaded everything LOL...I will let ya know how it comes out!

reply
jenn replied to jenn at Friday, June 10, 2011 5:07 PM
okay i have down loaded the wpf toolkit..how do i install it into visual studio..im sorry, but as i said earlier i am so very new at this
reply
jenn replied to Michael Detras at Friday, June 10, 2011 5:07 PM
okay..I have downloaded all the converter to go from VB to C..and I have downloaded the toolkit..but as I said earlier, I am very new to this and am not sure how to get the toolkit or the converter into my visual studio. I have them saved to a folder on D drive in hold before placing them on C drive because I am not sure which folder i am suppose to drop this in.
reply
Michael Detras replied to jenn at Friday, June 10, 2011 5:07 PM
Hi Jenn,

Are you sure you have downloaded the WPF Toolkit windows installer package (MSI)? Just run it and will will automatically install and you can find the controls in Visual Studio. As for the MoXaml Power Toys, you must change the downloaded installer from DOC to ZIP file extension, then run the installer. Just accept the default values. It will also be automatically added to Visual Studio.

Hope this helps,
Mike
reply
jenn replied to Michael Detras at Friday, June 10, 2011 5:07 PM
hi mike

i am so sorry to say this because i really need exactly what you are talking about here...and the thing of it all is is that i need it in 8 days:(..

I am trying so desperatly to get this to work ..but I guess I am just too new at this to understand. lol..i know very little about visual studio..*sigh*

the way you have it explained is not the problem..it is all well laid out and stuff, it really is just above what I can understand. First of all I started my project off in Visual Basic, only because it was what I started using 8 years ago..before I was so abruptly forced to put the whole adventure away. now, this is wrote in C..LOL...I barely know VB...never mind C! lol..

yes i did get the converter..but i do not understand what you mean by having to change Doc..to..or even how LOL..i right click on the file and go to properties..but then have to pick a program to open it *sigh*

I did download the toolkit..and did extract it..and in my toolbar it shows : Pointer, DataGrid,DatePicker and Calendar. I do not see all of these places you are talking about to change calendar template (cuz between you and me...that calendar in studio as it is is ugly beyond ugly LOL)

it is just so frustrating to finally FIND exactly what I need...to a Tee..and have such a hard time making it all happen :(
reply
Michael Detras replied to jenn at Friday, June 10, 2011 5:07 PM
Hi Jenn,

The MoXaml Power Toys installer is downloaded in .DOC format so you need to change it to .ZIP. If the .DOC extension is hidden, go to Folder and Search options (found in Explorer) and uncheck the "Hide extensions for known file types" check box. Rename the installer file and change the extension to .ZIP and extract the contents. Having read your situation, this will be a tough one.

Good luck!
Mike
reply
Mario replied to Michael Detras at Friday, June 10, 2011 5:07 PM
Hi Michael,

First of all, love the work you did with styling the Calendar.

I have one question/issue for you.

Say I have your Calendar and a ComboBox in a StackPanel (ComboBox then your Calendar, vertically), If I click on a day in the Calendar, then mouse over the ComboBox, it is not detecting the mouse over. It's as if the Calendar is capturing focus of input when it has it, and the user must click off of the calendar to restore focus to the outside controls. 

This is a problem I've noticed with updating the Calendar dynamically. If it doesn't have focus, it doesn't update.

Let me know if you've seen this, or have suggestions I can attempt.

Thanks,
-Mario
reply
Michael Detras replied to Mario at Friday, June 10, 2011 5:07 PM

Hi Mario,

 

Thanks for reading the article. Regarding the problem, I haven't encountered it yet before. I checked it again and you are right. The CalendarItem control is capturing the mouse when you select it. One thing that you could do is to override the PreviewMouseUp event on the MonthViewCalendar control and release the mouse capture. That is just a suggestion that you may try though, as I don't know if there are any possible side effects this could bring. Hope this helps.

 

Thanks,

Mike

reply
Jebby Fish replied to Michael Detras at Friday, June 10, 2011 5:07 PM
Hi,

This is a great article and a nice calendar. Thank you so much!
I am new to WPF and am trying to make use of this calendar.
I would like to use it as a user control but encounter issue (the calendar does not show up at all) when i compiled it as DLL and put it in one of the user control (for testing purpose, I just have an empty grid in this user control) i have created.

Would you please shed me some light on which direction should I look into?

Thank you so much in advance! :)
reply
Michael Detras replied to Jebby Fish at Friday, June 10, 2011 5:07 PM
Hi,

Thanks for reading the article. As for your problem, I don't have a clue on why you are encountering this. Could you give me more details like Visual Studio and .NET Framework you are using, any errors in Output Window when you build or rebuild the solution, does it happen in design-time or runtime, etc. Or could you upload a sample solution where you could reproduce the issue? Thanks!
reply
Jebby Fish replied to Michael Detras at Friday, June 10, 2011 5:07 PM
Hi,

Thanks for the prompt reply. I got this issue taken care of. Thank you! :)
Now I have another question, if I want to attach an event to the listbox (or listItem) for the appointments. How should I do it? I tried to put it in the resource.dictionary; however, I got the following error message:

Error   1   'ResourceDictionary' root element requires a x:Class attribute to support event handlers in the XAML file. Either remove the event handler for the PreviewMouseLeftButtonDown event, or add a x:Class attribute to the root element. Line 455 Position 29.  

Would you please shed me some light on this issue. I am sorry if this is a simple, basic question. I am a newbie in WPF. :)

THANKS!!!
reply
Michael Detras replied to Jebby Fish at Friday, June 10, 2011 5:07 PM
Hi,

Do you want to attach an event handler for the PreviewMouseLeftButtonDown event of the ListBox? If so, then you have to attach it programmatically (in code). You can't do it in the ResourceDictionary because this is the place where you put the default style for the Calendar.

So, in the OnApplyTemplate method, you can do this: listBox.PreviewMouseLeftButtonDown += MyHandler;
reply
Jebby Fish replied to Michael Detras at Friday, June 10, 2011 5:07 PM
wow...
yes... I wanna drag and drop the appointment. You are so smart... :D

May I ask how do I access the listBoxes which are defined in the Generic.xaml?

reply
Michael Detras replied to Jebby Fish at Friday, June 10, 2011 5:07 PM
I have to look again at the code because I forgot most of what I did already. I saw that the ListBox is defined in the CalendarDayButton template, not the Calendar. Unfortunately, this class is sealed (for valid reasons) so we can't get it on the OnApplyTemplate method using GetTemplateChild. You can traverse the visual tree if you want to.

I haven't implemented drag and drop for the calendar that I use in my application, so I can't give you an exact solution. Maybe you could use the CalendarDayButton instead of the ListBox to implement that behavior.
reply
Carl replied to Michael Detras at Friday, June 10, 2011 5:07 PM
Michael, I'm very new to WPF and XML/XAML and don't know how to construct the XAML files for the 3 new namespaces used in the Generic.XAML calendar template file that is in the WPFToolkit. Can you provide the syntax of the file?

Thanks
reply
Michael Detras replied to Carl at Friday, June 10, 2011 5:07 PM
Hi Carl,

Sorry for the late response. Have you solve your problem already? Can you give me more details about your problem? That would help a lot. You could also post in the forums. I'm sure you will get a timely answer. Thanks!
reply
Carl replied to Michael Detras at Friday, June 10, 2011 5:07 PM

Hi Michael,

 

Thanks for getting back to me, I have solved the original issue. I was not able to get your code to download when selecting the “Here” hyperlink, hyperlink actually worked up on the word “note”. I do have another question though, I have been playing around with your code to try to load appointments by date out of a SQL DB using LINQ when the app launches. I think the below code could be modified to do the task but have no clue how to write it. Any help would be greatly appreciated.

 

      public ObservableCollection<Appointment> Appointments

      {

 

        get { return (ObservableCollection<Appointment>)GetValue(AppointmentsProperty); }

        set { SetValue(AppointmentsProperty, value); }

      }

reply
Michael Detras replied to Carl at Friday, June 10, 2011 5:07 PM
Changing the control's code to load appointments from an SQL DB is valid. However, that would mean having a code tightly-coupled with a database implementation. I suggest you do it from outside the control, in your application. Load the dates from the database, create the calendar, then fill up the Appointments property. If you need to show other data, then you can add more properties to the Appointment class.
reply
akshay replied to Michael Detras at Friday, June 10, 2011 5:07 PM
Hey

I m new at Visual studio 2010.. and i want to make the calendar like the one you have made in this article... first of all let me say its a fantastic article... but all these commands are invalid in wpf 2010... so is it possible if you can help post the commands with visual studio 2010... the Monthcalendar is already included in visual studio 2010.... but for some reason i cant figure out a way to make changes to dimensions... it still shows only one calendar... that too in a very smalll rectangle..... any help will be gretly appreaciated.

Thanks

Akshay Chaudhary
reply
Gilles replied to akshay at Friday, June 10, 2011 5:07 PM
Hi there,
Great article you wrote there. It's what I was looking for. However, in my WPF app, I need to display events (Appointments in your terminology) which span multiple days. I don't really see how I could modify your control to take this into account. Maybe you've got an idea?
Let's say the event spans december 13th, 14th and 15th. I could add 3 different single day events. However, I want to visually distinguish between the start day, the end day and the days inbetween. How can I do that?
reply
Article Discussion: Styling the WPF Calendar to Resemble Outlook's Month View Calendar
Robert replied to Michael Detras at Friday, June 10, 2011 5:07 PM
Hej Michael, Great job with this calendar. 

Michael. I got so far, that I made a new method (GetMyAppointments()) in to the MonthViewCalendar class, which I call from MainWindow. I made the new appointments and I added to the Appointments list, but I do not know how to call the AppointmentConvert method with the new information, and in this case, I can't show my appointments in the calendar.
I tried to watch trough step by step, how you did it from the AppointmentWindow, where your code is jumping from the PropertyChanged method to the AppointmentConverter. I tried to use the same line in my method, but I get an error.

Thank you in anticipation for your help.
Sincerely 
Robert 
reply
Michael Detras replied to Robert at Friday, June 10, 2011 5:07 PM
Hi Robert,

Thanks for reading the article. If I understand it correctly, the UI was not informed that the Appointments list has been changed. Usually, it will only take raising the PropertyChanged event to solve this. What kind of error are you getting? A short code snippet will also help. Thanks!

Michael
reply
Robert replied to Michael Detras at Friday, June 10, 2011 5:07 PM
Hi Michael,
Thank you for your fast answer.
The error I catch is: "Object reference not set to an instance of an object"
I get this error when I copy the PropertyChanged code line from your override OnMouseButtonClick method.

I will send you the whole method I wrote later on today, if it's needed.
Thanks,
Robert

reply
Michael Detras replied to Robert at Friday, June 10, 2011 5:07 PM
Yes please upload or post your code snippet somewhere and give me a link so that I can check. Thanks!
reply
Robert replied to Michael Detras at Friday, June 10, 2011 5:07 PM

Hi Michael,

 

Here are the code you needed. (Check out the .docx file)

Thank you for your help.

Open here

reply
Robert replied to Robert at Friday, June 10, 2011 5:07 PM
Hi Michael,

Did you find the snippet? Could you confirm it?

regards
Robert
reply
Robert replied to Michael Detras at Friday, June 10, 2011 5:07 PM
Hi Michael, 
Did you find the snippet? Could you confirm it? 

regards 
Robert
reply
Michael Detras replied to Robert at Friday, June 10, 2011 5:07 PM
Hi Robert,

Yes, I found the code snippet. I would like to create a similar scenario on my own machine so that I can give a definite answer, but currently don't have the time to do so. I'll try it out later. It might be related to timing since the PropertyChanged event is still null after the Loaded event of the Window is raised. I'll get back to you later. Thanks!

Regards,
Michael
reply
Michael Detras replied to Robert at Friday, June 10, 2011 5:07 PM
Hi Robert,

I see that you've added a MonthViewCalendar instance variable to your MainWindow class. And you've called your method in the Loaded event handler. The problem is that the MonthViewCalendar you just defined is not really a child/descendant of the main window, thus the bindings aren't set even after the window is loaded. I assume you put another MonthViewCalendar in the MainWindow XAML, right? Give it a name and use that to call your method, and remove the other MonthViewCalendar variable. Hope this helps.

Best regards,
Michael
reply
Robert replied to Michael Detras at Friday, June 10, 2011 5:07 PM
Hi Michael,
Thank you so much using time on me and my pitty scool project. I do not know how to do that. I used your program part as template and I did not change anything in it, except the small method I wrote. I can only program C# and I do not know anything about xaml or xml. I do not understand what you mean. Is it possible for you to explain it on "dummy" language?
I really would like to make it work in my project.

Sorry for using your time!

Robert
reply
Michael Detras replied to Robert at Friday, June 10, 2011 5:07 PM
Hi Robert,

I see, there is nothing to be sorry of. If you open the MainWindow.xaml file, you could see the following line:

 

<local:MonthViewCalendar/>

You could give it a name like this:

<local:MonthViewCalendar x:Name="calendar"/>

And the MainWindow.xaml.cs would look like this:

public partial class MainWindow : Window
{
  public MainWindow()
  {
    InitializeComponent();
  
    Loaded += new RoutedEventHandler(MainWindow_Loaded);
  }
  
  private void MainWindow_Loaded(object sender, RoutedEventArgs e)
  {
    calendar.LoadAppointments();
  }
}

Michael

reply
Robert replied to Michael Detras at Friday, June 10, 2011 5:07 PM
I found the problem. 
There should be:
            Loaded += new RoutedEventHandler(Window_Loaded);
and not
            Loaded += new RoutedEventHandler(MainWindow_Loaded);

Its working Michael. So we can conclude, that this is one of the way to load appointment in to the Month Calender View from a saved database or datafile.

Thank you for your help!

Friendly regards 
Robert
reply
Robert replied to Michael Detras at Friday, June 10, 2011 5:07 PM
Hey Michael,

I have a final question.
For some kind of mysterious reason, I am getting my appointments two times for the same day. I checked the lists, they made correctly. 
Any suggestion?

kind regards 
Robert
reply
Maarten replied to Robert at Friday, June 10, 2011 5:07 PM
Hi,

This is my first application ever in WPF and I'm doing this for schoolwork.

My question was this: I'm allways getting this error "Property 'CalendarItemStyle' was not found in type 'control'"

Hope to hear you soon.

Kind regards

reply
Robert replied to Maarten at Friday, June 10, 2011 5:07 PM
Hej Maarten,

Did you get the openSource CustomCalendar from here? Did you download and installed the WPFToolkit?

Regards Robert
reply
Maarten replied to Robert at Friday, June 10, 2011 5:07 PM
Where can I find those? I've downloaded the WPF Toolkit but i can't install it.

Thanks in advance!
reply
Maarten replied to Maarten at Friday, June 10, 2011 5:07 PM
Ok sorry for that, the WPF Toolkit was allready installed. I can't find the CustomCalender though.

reply
Robert replied to Maarten at Friday, June 10, 2011 5:07 PM
Hej,

Try to look just under Figure 9.

there is a link.

regards

Robert
reply
Sreenath KV replied to Michael Detras at Friday, June 10, 2011 5:07 PM
I want to add MouseLeftButtonDown event of the ListBox but was not able to do it. I tried the method you mentioned for Jebby Fish. I want to popup another form when i click a list box item. how can i do it? i am new to WPF. can you explain it in a  'dummy language' .....
reply
Sreenath KV replied to Michael Detras at Friday, June 10, 2011 5:07 PM
Also , i would like to know how to delete an appointment that have been added to the list.
reply