500 likes | 584 Views
Under the hood in Silverlight’s controls skinning framework. Gill Cleeren Microsoft Regional Director – MVP ASP.NET Ordina .NET Architect gill.cleeren@ordina.be. About Gill. .net architect Ordina (ordina.be) Microsoft Regional Director (theregion.com) MVP ASP.net Writing: .net magazine
E N D
Under the hood in Silverlight’s controls skinning framework Gill Cleeren Microsoft Regional Director – MVP ASP.NETOrdina .NET Architect gill.cleeren@ordina.be
About Gill • .net architect Ordina (ordina.be) • Microsoft Regional Director (theregion.com) • MVP ASP.net • Writing: • .net magazine • Blogs • MSDN • Speaking: • TechDays • Usergroups(Visug, Biwug, Besug) • Ineta speaker • Blog: www.snowball.be • Email: gill.cleeren@ordina.be • Twitter: gillcleeren • MSN: gillcleeren@hotmail.com
Agenda It’s all about being in control • Usercontrols • Demo • Controls with “Style” • Demo
Agenda It’s all about being in control • Skinning controls • Control templates • Demo: the Round Button • A control from scratch • Demo • Parts and states model and the Visual State Manager • Demo • In control of states from code-behind • Demo • VSM loves Blend • Demo
UserControl: the easy-cheesy one • Organize small portions of UI in more manageable components • Fixed look with some logic • Split large XAML blocks into smaller parts • Reuse xaml/logic in multiple places, even other projects • Similar to ASP.NET usercontrols • 3 step process: • Define appearance • Define behavior • Call the control
UserControl: the easy-cheesy one • Platform Support • <UserControl x:Class=“MyControl”> … </> • public partial class MyControl : UserControl {} • XAML is optional • DependencyProperty use is advised
DependencyProperty: a sidestep • Type of property that can be used with DataBinding, Styling, Animations... • Its value can rely on one or more sources (StoryBoard, Binding...) • 2 step process to create a DP • Define the property • Register the property with the Dependency system • Not only for UserControls (ie. We’ll need it further in this talk!)
DependencyProperty public static readonlyDependencyPropertyIsLockedProperty = DependencyProperty.Register( "IsLocked", typeof(bool), typeof(LockableTextBox), new PropertyMetadata(new PropertyChangedCallback(OnIsLockedChanged)) ) public bool IsLocked { get { return (bool)(GetValue(IsLockedProperty)); } set { SetValue(IsLockedProperty, value); } } private static void OnIsLockedChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) { LockableTextBox textBox = (LockableTextBox)(o); textBox.UpdateUI(); }
Demo Building and using a usercontrol: a Lockable TextBox
Usercontrols take-aways • Bundle UI + behavior • Easy reuse • Split large files (XAML/C#) • Similar to ASP.NET
Controls with “Style”: the handy one • Share property values across multiple elements • Similar to CSS • Needed to avoid maintenance nightmare • Implemented as “Style” property with Setters collection • Available on FrameworkElement • No “Based-on” and “Default styles” at this point, sadly
Demo Styling controls:A small form with “Style”
Styling take-aways • Only change UI properties • Bundled and located in one place • Increases maintainability
Skinning controls: the powerful one • Styling is somewhat limited • A template allows for complete flexibility without losing functionality of the control
ControlTemplates & Co • Every control exposes a Template property (of ControlTemplate type) • Gives you a clean slate to start from • Possible to have data binding between Control and ControlTemplate using TemplateBinding • Also possible to instruct Silverlight where to put the content using ContentPresenter
Demo ControlTemplate, TemplateBinding and ContentPresenter: “I’ve had it with those rectangle buttons...”
Control template take-aways • Swap in new visual tree for a control • TemplateBindings • ContentPresenter
Taking it a step further: a custom control from scratch • The "Built-in" Look • generic.xaml • Assembly resource in controls dll • Contains resource dictionary with built-in styles • DefaultStyleKey • Value is the Type of control • Indicates which generic.xaml & which style in that generic.xaml
Demo A complete custom control: A not-so-good-looking start
Trouble in paradise • A: “Question: My control can only be normal?” • B: “Good question! Custom control doesn’t provide ability to create a “Clicked”, “MouseOver”... State” • A: • B: “You need the Parts and States Model” • A:
Introducing... • Parts and state model • Parts • States • Where to get the states? • MSDN • Reflection
The Parts and States Model (PSM) • Goals • How to structure your control • Defined separation between logic & visuals • Explicit control contract • Recommended pattern • Not enforced by runtime • Will be supported by Blend
The Parts and States Model (PSM) and the Visual State Manager • VSM relies on variety of components: the PSM • Ensures clean separation between visuals and logic • VSM is used to manage change between states: • State-based effect (larger button when mouse-over) • Transitioning effect (from mouse-over to normal)
PSM: the Parts DownRepeatButton Thumb UpRepeatButton Track • Named element in template: “working parts” • Not in every control • Code manipulates element in some way
The parts of the slider control [TemplatePart(Name="HorizontalTemplate", Type=typeof(FrameworkElement))] [TemplatePart(Name="HorizontalTrackLargeChangeIncreaseRepeatButton", Type=typeof(RepeatButton))] [TemplatePart(Name="HorizontalTrackLargeChangeDecreaseRepeatButton", Type=typeof(RepeatButton))] [TemplatePart(Name="HorizontalThumb", Type=typeof(Thumb))] [TemplatePart(Name="VerticalTemplate", Type=typeof(FrameworkElement))] [TemplatePart(Name="VerticalTrackLargeChangeIncreaseRepeatButton", Type=typeof(RepeatButton))] [TemplatePart(Name="VerticalTrackLargeChangeDecreaseRepeatButton", Type=typeof(RepeatButton))] [TemplatePart(Name="VerticalThumb", Type=typeof(Thumb))] ... public class Slider : RangeBase { ... }
PSM: the States MouseOver Pressed [TemplateVisualState(Name="Normal", GroupName="CommonStates")] [TemplateVisualState(Name="MouseOver", GroupName="CommonStates")] [TemplateVisualState(Name="Pressed", GroupName="CommonStates")] [TemplateVisualState(Name="Disabled", GroupName="CommonStates")] [TemplateVisualState(Name="Unfocused", GroupName="FocusStates")] [TemplateVisualState(Name="Focused", GroupName="FocusStates")] public class Button : ButtonBase { ... } • Visual look of control in a particular state
PSM: the State Group • Set of mutually exclusive states • Different state groups are orthogonal
State groups for Button <ControlTemplate x:Key="ButtonTemplate"TargetType="Button"> <Grid> <VisualStateManager.VisualStateGroups> ... </VisualStateManager.VisualStateGroups> <Border x:Name="ButtonBorder" BorderBrush="Orange" BorderThickness="3“ CornerRadius="15"> <Border.Background> <SolidColorBrush x:Name="ButtonBackgroundBrush" Color="Red" /> </Border.Background> <ContentPresenter ... /> </Border> </Grid> </ControlTemplate>
State groups for Button <ControlTemplate x:Key="ButtonTemplate"TargetType="Button"> <Grid> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> ... </VisualStateGroup> <VisualStateGroup x:Name="FocusStates"> ... </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Border x:Name="ButtonBorder" BorderBrush="Orange" BorderThickness="3" CornerRadius="15"> ... </Border> </Grid> </ControlTemplate>
State groups for Button <ControlTemplate x:Key="ButtonTemplate"TargetType="Button"> <Grid> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="MouseOver"> ... </VisualState> <VisualState x:Name="Normal"> ... </VisualState> </VisualStateGroup> <VisualStateGroup x:Name="FocusStates"> ... </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Border x:Name="ButtonBorder" BorderBrush="Orange" BorderThickness="3“ CornerRadius="15"> ...
State groups for Button <ControlTemplate x:Key="ButtonTemplate"TargetType="Button"> <Grid> <VisualStateManager.VisualStateGroups> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="MouseOver"> <Storyboard> <ColorAnimation Duration="0:0:0“ Storyboard.TargetProperty="Color" To="Orange“ Storyboard.TargetName="ButtonBackgroundBrush“ /> </Storyboard> </VisualState><VisualState x:Name="Normal"> ... </VisualState> </VisualStateGroup> <VisualStateGroup x:Name="FocusStates"> ...
PSM: the Transitions VisualTransition MouseOver Pressed • Visual look of control as it goes between states • Reverts automatically
PSM: the Transitions • VisualTransition class • Contains duration for automatic transition animations • Automatic Transition Animations • Generate linear transitions for properties set in VisualState by Color, Point, & Double animations, not for Object animations
Transitions for the Button: Default transition <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualStateGroup.Transitions> <VisualTransition GeneratedDuration="0:0:0.2" /> </VisualStateGroup.Transitions> <VisualState x:Name="MouseOver"> <Storyboard> <ColorAnimation Duration="0:0:0" Storyboard.TargetName="ButtonBackgroundBrush" Storyboard.TargetProperty="Color" To="Orange" /> </Storyboard> </VisualState> .....
Transitions for the Button:Specific transition <VisualStateGroup x:Name="CommonStates"> <VisualStateGroup.Transitions> <VisualTransition To="MouseOver"GeneratedDuration="0:0:0.5" /> <VisualTransition From="MouseOver"GeneratedDuration="0:0:0.1" /> </VisualStateGroup.Transitions> .....
Transitions for the Button:Custom transition <VisualStateGroup.Transitions> <VisualTransition To="Normal" From="MouseOver"GeneratedDuration="0:0:0.7"> <Storyboard> <DoubleAnimationUsingKeyFrames Storyboard.TargetName="ScaleTransform" Storyboard.TargetProperty="ScaleX"> <LinearDoubleKeyFrameKeyTime="0:0:0.5" Value="0" /> <LinearDoubleKeyFrameKeyTime="0:0:0.7" Value="1" /> </DoubleAnimationUsingKeyFrames> </Storyboard> </VisualTransition> </VisualStateGroup.Transitions>
Selecting The VisualTransition • Types of transitions: (MouseOver Pressed) • From/To • <VisualTransition To=“Pressed” From=MouseOver” …> • To • <VisualTransition To=“Pressed” … > • From • <VisualTransition From=“MouseOver” … > • Default • <VisualTransition …> • Selects most specific transition
Demo Visual State Manager: Creating a new checkbox
Recap: VSM • ViewStateManager • VisualStateGroups • VisualStates • Transitions • Generated (not for object animations) • Specific
VisualStateManager from code-behind VisualStateManager GoToState() VisualStateGroups Defined in template Called in control code Not limited to XAML: more options in code-behind
Visual State Manager from code-behind • Building blocks: • Control contract metadata • TemplatePart • TemplateVisualState • NOT used by runtime. Leveraged by tools. • public static VisualStateManager.GoToState() • Manages visual state change logic & transitions • public override void OnApplyTemplate() • Called when new template has been applied
Demo VSM from code-behind
VSM Code-behind take-aways • TemplatePart & TemplateVisualState • GoToState • OnApplyTemplate
Demo VSM in Blend
Summary • User controls: for combining controls and easy reuse • Styling: for changing normal properties on a scalable manner • Control template: allows for overriding complete look and feel • Visual State Manager: extending the control template to manage states
Resources • Scorbs.com • Silverlight in Action (Manning, 2008) • MSDN library
Q&A Did you understand everything...?
Thank you Under the hood in Silverlight’s controls skinning framework Gill Cleeren Microsoft Regional Director – MVP ASP.NETOrdina .NET Architect gill.cleeren@ordina.be