WPF and Silverlight have the cool idea of 'Lookless controls' which means you can skin a control in whichever way you like. Or in other words the UI rendering logic of a WPF control lives totally in a seperate world than the control's functionality. This enables a WPF applications capaibility to dress up in totally different skins and layouts at the run time.
So let me explain the creation of a simple custom control by taking the example of a Marquee control. Hope you are well aware of the HTML Marquee tag. I am explaining the CustomControl concept of WPF with Marquee control as an example.
Step to Create a custom control with VS2008
The above step will give you the class file and Generic.xaml added to the project.
Who is your control Parent?First I should choose the base class from which my control has to derive from. I am seeing the Marquee as a control which holds up a content element always and the content gets scrolled horizontally. So I can say that ' Marquee control has a Content' so lets write that statement in C#.
public class Marquee :
ContentControlWhat is the default look of your control?Next step is to define the visual elements which builds up the default look. My idea here is to put a Canvas and make the content scroll inside the canvas using DoubleAnimation on Canvas.Left attached property. So the default template can be writen as shown in the XAML.
<Style TargetType="{x:Type local:Marquee}"> <Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:Marquee}"> <Canvas>
<ContentPresenter x:Name="PART_Content"/>
</Canvas>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
You can see from the XAML that the
ContenPresenter is having a name so that we can find the reference of this control inside the control logic. So here we are making a mutual contract between the Control logic and the UI logic that we will always expect a control named PART_Content in the control template. So anybody who is goinging to re-template this would be considering this fact.
Using the following code we can find the instance of the above metioned contentpresenter
public override void OnApplyTemplate()
{ _contentPresenter = Template.FindName("PART_Content", this) as FrameworkElement; Marquee Logic Implementation private void Animate()
{ if (IsLoaded)
{ _doubleAnimation.From = this.ActualWidth;
_doubleAnimation.To = -_contentPresenter.ActualWidth;
_doubleAnimation.RepeatBehavior = RepeatBehavior.Forever;
_doubleAnimation.Duration = Duration;
Storyboard.SetTargetProperty(_doubleAnimation, new PropertyPath("(Canvas.Left)")); _storyBoard.Children.Add(_doubleAnimation);
_storyBoard.Begin(_contentPresenter,true);
}
}
The animation code has taken the actualWidth of the content and animate the Canvas.Left from control's rightside to left.
Sample ApplicationCheck out the
XBAP application - LIVE DEMO running this marquee. One marquee with a TextBlock as its content and another with an ItemsControl as its content.
<lib:Marquee Duration="00:00:10" RenderTransformOrigin="0.5,0.5" HorizontalAlignment="Stretch">
<TextBlock FontSize="18" FontWeight="Bold" Foreground="#FF000000" Text="Sample Marquee Text" />
</lib:Marquee>
<lib:Marquee Duration="00:00:10" RenderTransformOrigin="0.5,0.5" HorizontalAlignment="Stretch">
<ItemsControl x:Name="lstPhotos" ItemsTemplate="{StaticResource someCoolTemplate}"/></lib:Marquee>
