views:

41

answers:

3

I am experimenting with derived custom controls, and I created what I thought would be the simplest possible derivation:

  • I created a custom control project in VS 2010 and changed the base class for CustomControl1 from Control to Calendar.

  • Then I went into Generic.xaml and removed the default Style created for CustomControl1.

  • Finally I created a WPF app to consume the control.

When I add the custom control to the app's MainWindow, I had expected to see a regular WPF calendar, since I had derived from Calendar and made no changes to the Calendar control templates.

Instead, nothing shows up at design time or run time. MainWindow remains empty. I am not sure what is going on, but it is pretty obvious that I have made a faulty assumption somewhere along the line.

Can anyone clear this up for me? Thanks for your help.

BTW--why am I doing this? I am extending the Calendar control, but I will only need to modify the CalendarDayButton control template. Before I get to my modifications, I figure I should be able to display the unmodified Calendar first. Like I said, I think I'm making a faulty assumption somewhere.

CustomControl1.cs Here is the code for CustomControl1:

using System.Windows;
using System.Windows.Controls;

namespace WpfCustomControlLibrary1
{
     public class CustomControl1 : Calendar
     {
          static CustomControl1()
          {
               DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl1), new FrameworkPropertyMetadata(typeof(CustomControl1)));
          }
     }
}

Generic.xaml Here is the markup for Generic.xaml, which is located in the control's Themes folder:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfCustomControlLibrary1">


</ResourceDictionary>

MainWindow Finally, here is the MainWindow.xaml markup:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 

        xmlns:WpfCustomControlLibrary1="clr-namespace:WpfCustomControlLibrary1;assembly=WpfCustomControlLibrary1" Title="MainWindow" Height="350" Width="525">
    <Grid>
        <WpfCustomControlLibrary1:CustomControl1 />
    </Grid>
</Window>

WpfApplication1 contains a reference to the WpfCustomControlLibrary1 project.

+3  A: 

DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl1), new FrameworkPropertyMetadata(typeof(CustomControl1)));

->What this line says is that CustomControl1 has its own style defined in Generic.xaml

Then I went into Generic.xaml and removed the default Style created for CustomControl1.

-> What this does is remove the style for CustomControl1

So your control has no style so it shows nothing :D

Rather than removing the style from generic.xaml, you should copy the the style of the Calender control and change TargetType to CustomControl1 or create a new style and add BasedOn Calender

Edit to add a little more info to David's answer below for people having a look down the road

<Style TargetType="{x:Type local:FsCalendar}" BasedOn={x:Type Calender}>
    <Setter Property="CalendarDayButtonStyle" Value="{StaticResource FsCalendarDayButtonStyle}" />
</Style>

This is all you need in the style. BasedOn will take care of copying everything from the default style and it will also take care of different themes. If you copy the style from the default theme of calender you will break the look for all the themes except for the one from which you copied the 'default' style.

NVM
@David. This is your answer
Berryl
Thanks--Calendar still isn't appearing. If I am modifying only the CalendarDayButton, do I have to include all Calendar control tempolates in my Generic.xaml? Michael Detras' custom control on EggheadCafe (http://www.eggheadcafe.com/tutorials/aspnet/88c6f252-ba7f-4789-97e8-1bd7690ca385/styling-the-wpf-calendar-to-resemble-outlooks-month-view-calendar.aspx) seems to include only the control templates he modifies.
David Veeneman
Oops-- on second look, Detras includes all templates. I think I have my answer.
David Veeneman
I think its much better to just create an empty style and add BasedOn Calender. Then you wont be stuck with the same look for the calender even when the current OS theme changes the look of all your other controls. You should change the ControlTemplate in the new Style only if you actually need to change the completely differently layout for your control. If you do change the ControlTemplate in the style keep in mind that best practice in my opinion is that you have Styles for all the themes your app supports (read atleast the themes which come bundeled with WPF)
NVM
Sometimes this is simply a lot of work so what I do is remove everything from a style that hardcoded colors etc and only keep those things in which I can reference some standard colors etc.. Hope this helps
NVM
+1  A: 

I found my answer--thanks to NVM for all the help! This applies to controls generally, but it applies particularly to the Calendar control. If you are going to modify only part of the control, you don't have to include all of the constituent control templates.

But you do have to include the main control template, which you point to your custom control, and you have to establish a chain from the main control to the template you want to modify. In the case of my Calendar control, I need to modify only the CalendarDayButton template to implement the changes I want to make. So, here is what I did:

  • I included the main Calendar template, and point that toward my custom control.

  • Then, to get down to the CalendarDayButton, I added a property setter to point my main Calendar style's CalendarDayButtonStyle property to my custom CalendarDayButton style.

Here is what the main Calendar style declaration in my Generic.xaml file ends up looking like:

<!-- Calendar Style -->
<Style TargetType="{x:Type local:FsCalendar}">
    <Setter Property="CalendarDayButtonStyle" Value="{StaticResource FsCalendarDayButtonStyle}" />
...
</Style>

The remainder of the main Calendar style is unchanged--it is a copy of the default style.

BTW, the CalendarDayButton style definition must appear before the main Calendar style definition in Generic.xaml, or the main Calendar style won't be able to find it.

I have written a Code Project Article titled Extending the WPF Calendar Control. It walks through the step involved in extending a complex control like the WPF Calendar. Hopefully, it will help others who are grappling with the same issues.

David Veeneman
A: 

BTW, I have since discovered the Style.BasedOn property, which will let you derive a style from an existing style without having to repeat the base style. There is a good blog post on it here.

David Veeneman