Page view counter

Jesse Liberty - Silverlight Geek

More Signal Less Noise

RC0 & ContentPresenter

 

The breaking changes document points out that ContentPresenter now derives from FrameworkElement and thus loses 18 public properties  as well as TextAlignment, TextDecorations and TextWrapping. All of this calls for a bit of rewriting if you've used this powerful and useful control, and there was a request in one of the internal discussion lists that this be called out to developers; hence this blog entry.

VideoStartSerendipitously, I have a video that uses the ContentPresenter control.

The ContentPresenter control is the enabling control behind entering "Content" rather than text in the standard Button, CheckBox and so forth.  Until RC0, you could have set the fontsize, FontWeight, etc. in the ContentPresenter itself, though that never would have been good programming practice, as it always made more sense to leave that for the client (the programmer using your control.

Thus, in my template, I set few properties on the ContentPresenter itself, and when I use the control that the ContentPresenter is part of (the Button) I can set the characteristics of the content, which are then passed to the ContentPresenter. This will continue to work in RC0

Let me be explicit, if you used ContentPresenter as intended (note the Beta documentation which states "Typically, you use the ContentPresenter directly within the ControlTemplate of a ContentControl to mark where the content is to be added.") then you would probably not have used any of the properties that are no longer available to you, as you would have wanted, as I did, to leave that flexibility to the consumer of your control.

On the other hand, if you did use those properties, the fix is fairly simple, you just remove the properties from the content control, and if you need the property set, you set it when you call the control

An example will make this explicit.  Assume you define your button template in App.xaml as follows (the following listing is abridged):

   1: <ControlTemplate x:Key="RoundButton" TargetType="Button">
   2:     <Grid>
   3:         <vsm:VisualStateManager.VisualStateGroups>
   4:         </vsm:VisualStateManager.VisualStateGroups>
   5:         <Ellipse >
   6:         </Ellipse>
   7:         <ContentPresenter Margin="0,10,0,0" x:Name="RoundButtonContent" 
   8:                           RenderTransformOrigin="0.5,0.5" 
   9:                           HorizontalAlignment="Center" 
  10:                           VerticalAlignment="Center"
  11:                           FontFamily="Comic Sans MS"                           
  12:                           FontSize="24"
  13:                           FontWeight="Bold"
  14:                           Foreground="#FFFF0000">
  15:             <ContentPresenter.RenderTransform>
  16:                 <TransformGroup>
  17:                 </TransformGroup>
  18:             </ContentPresenter.RenderTransform>
  19:         </ContentPresenter>
  20:     </Grid>
  21: </ControlTemplate>

Focusing on lines 11-14, you have to ask why you would hard code into the ContentPresenter portion of your button the font characteristics and the color. This would mean that every Button the user wants to create must have a 24 point Comic Sans MS Bold red font, which seems a little restrictive.

In any case, starting in RC0 and consistent with WPF, this is no longer legal Silverlight code, and you'll now need to change your ContentPresenter definition to remove these lines. But that is a good thing, they belong instead in the xaml file that uses your button. Thus, the definition of the Button becomes:

   1: <ControlTemplate x:Key="RoundButton" TargetType="Button">
   2:     <Grid>
   3:         <vsm:VisualStateManager.VisualStateGroups>
   4:         </vsm:VisualStateManager.VisualStateGroups>
   5:         <Ellipse >
   6:         </Ellipse>
   7:         <ContentPresenter Margin="0,10,0,0" x:Name="RoundButtonContent" 
   8:                           RenderTransformOrigin="0.5,0.5" 
   9:                           HorizontalAlignment="Center" 
  10:                           VerticalAlignment="Center">
  11:             <ContentPresenter.RenderTransform>
  12:                 <TransformGroup>
  13:                 </TransformGroup>
  14:             </ContentPresenter.RenderTransform>
  15:         </ContentPresenter>
  16:     </Grid>
  17: </ControlTemplate>

and the instantiation of two RoundButtons might look like this (in, e.g., Page.xaml):

   1: <Button x:Name="Go" 
   2:         HorizontalAlignment="Right" 
   3:         VerticalAlignment="Stretch" 
   4:         Width="109" Grid.Row="5" Content="Go!" 
   5:         Template="{StaticResource RoundButton}" 
   6:         Foreground="#FF00FF00" 
   7:         FontFamily="Georgia" 
   8:         FontSize="36" 
   9:         FontWeight="Bold"/>
  10: <Button x:Name="Stop"
  11:         HorizontalAlignment="Stretch" 
  12:         VerticalAlignment="Stretch" 
  13:         Grid.Column="1" Grid.Row="5" 
  14:         Content="Stop!" 
  15:         Template="{StaticResource RoundButton}" 
  16:         Foreground="#FFFF0000" 
  17:         FontFamily="Comic Sans MS" 
  18:         FontSize="18" 
  19:         FontWeight="Semi-Bold"/>

This allows for the creation of two RoundButtons, but each with content that has a different font family, size, weight and color:

 ToRoundButtons

Generated Duration

Note that another small breaking change in RC0 is that within the definition of VisualStateGroups, the Duration property of Transitions has been renamed to GeneratedDuration, thus, the example code must change so that the VisualTransition Durations are now marked as Generated Transitions

Beta Code

   1: <vsm:VisualStateManager.VisualStateGroups>
   2:     <vsm:VisualStateGroup x:Name="FocusStates">
   3:         <vsm:VisualState x:Name="Unfocused"/>
   4:         <vsm:VisualState x:Name="Focused"/>
   5:     </vsm:VisualStateGroup>
   6:     <vsm:VisualStateGroup x:Name="CommonStates">
   7:         <vsm:VisualStateGroup.Transitions>
   8:             <vsm:VisualTransition Duration="00:00:00.2000000"/>
   9:             <vsm:VisualTransition Duration="00:00:00.1000000" To="Disabled"/>
  10:             <vsm:VisualTransition Duration="00:00:00.1000000" From="Disabled"/>
  11:         </vsm:VisualStateGroup.Transitions>

RC0 Code

   1: <vsm:VisualStateManager.VisualStateGroups>
   2:     <vsm:VisualStateGroup x:Name="FocusStates">
   3:         <vsm:VisualState x:Name="Unfocused"/>
   4:         <vsm:VisualState x:Name="Focused"/>
   5:     </vsm:VisualStateGroup>
   6:     <vsm:VisualStateGroup x:Name="CommonStates">
   7:         <vsm:VisualStateGroup.Transitions>
   8:             <vsm:VisualTransition GeneratedDuration="00:00:00.2000000"/>
   9:             <vsm:VisualTransition GeneratedDuration="00:00:00.1000000" To="Disabled"/>
  10:             <vsm:VisualTransition GeneratedDuration="00:00:00.1000000" From="Disabled"/>
  11:         </vsm:VisualStateGroup.Transitions>

 

The changes are on lines 8, 9 and 10 in the snippet above. 

Comments

Psychlist1972 said:

Hi Jesse

I'd like to point out a use that I don't consider a design flaw: providing VSM styles for buttons. In those, I had the properties on the content presenter, but they were bound to properties of the control itself. (That was the default behavior when creating the style using vsm). They weren't hard-coded in the style.

Now I need to find another way to get the textblock inside the button to have the correct alignment, font etc. as alignment infomration is no longer available at the button level and the rest of the required values do not currently appear to cascade down to the CP properly.

Haven't tried any of the obvious workarounds yet (or regenerating the style using RC0), but will when I get a second. Unfortunately, some of those workarounds would restrict the button to only the content I specifically put in the style. Not great there, and defeats the purpose of the contentpresenter.

Pete

# September 28, 2008 7:39 PM

2008 September 29 - Links for today « My (almost) Daily Links said:

Pingback from  2008 September 29 - Links for today &laquo; My (almost) Daily Links

# September 29, 2008 2:51 AM

Silverlight news for September 29, 2008 said:

Pingback from  Silverlight news for September 29, 2008

# September 29, 2008 11:54 AM

royhiggs said:

I think it does make sense to want to style the content of a button inside your button style. That way if you want to have a button control that reuses the same style across your application you can define it in the button style and not require the developer to set the font settings every time they use the button. That is the whole point of a style.

This wouldn't be so bad except that in Silverlight there is no BasedOn so I can't even add a style to the content presenter resources for the TextBlock that is based on my standard style for my buttons. So now I'm relegated to copy/paste which seems to just defeat the whole purpose of being able to have styles.

I guess I'll have to go back to the drawing board to figure out how to get consistent buttons in my application.

# September 29, 2008 6:41 PM

royhiggs said:

Also, Button doesn't have TextWrapping or TextAlignment properties so how should those be set in a button template using ContentPresenter?

# September 29, 2008 8:20 PM

Community Blogs said:

Boyan Mihaylov on SL/Amazon, David Hyde with SL Stock Portfolio, Chris Anderson with SL LOB app, Jesse

# September 30, 2008 2:00 AM

Silverlight, RC0 & ContentPresenter | DavideZordan.net said:

Pingback from  Silverlight, RC0 & ContentPresenter | DavideZordan.net

# September 30, 2008 5:32 PM

Jesse Liberty - Silverlight Geek said:

One way that many developers like to create styles and templates for controls is to modify the existing

# October 3, 2008 12:46 PM

Microsoft Weblogs said:

One way that many developers like to create styles and templates for controls is to modify the existing

# October 3, 2008 1:19 PM

Mirrored Blogs said:

One way that many developers like to create styles and templates for controls is to modify the existing

# October 3, 2008 1:50 PM

eXistenZ said:

Like Psychlist1972 said this is kind of contradictory to the idea of a style. On the other hand I can see that the content needed to be styled on the template level as a button can have any content in silverlight. So microsoft should just consider a template set, runntime overwrite model. Set the style for the content in the template but nevertheless you can overwrite it on a runntime object or in the corresponding xaml.

# October 24, 2008 3:14 AM

VaneS Blog said:

Recently I made update on my dev machine with the SP1 for Visual Studio 2008 and Silverlight-2. I made

# October 26, 2008 6:29 AM