David Veeneman
David Veeneman

Reputation: 19122

Getting started with a derived custom control?

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

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.

Upvotes: 1

Views: 2715

Answers (3)

NVM
NVM

Reputation: 5552

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

->What this line says is that CustomControl1 has its default 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 default 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.

Upvotes: 4

David Veeneman
David Veeneman

Reputation: 19122

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.

Upvotes: 0

David Veeneman
David Veeneman

Reputation: 19122

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.

Upvotes: 1

Related Questions