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. 

About Jesse Liberty

Jesse Liberty has three decades of experience writing and delivering software projects and is the author of 2 dozen books and a couple dozen online courses. His latest book, Building APIs with .NET will be released early in 2025. Liberty is a Senior SW Engineer for CNH and he was a Senior Technical Evangelist for Microsoft, a Distinguished Software Engineer for AT&T, a VP for Information Services for Citibank and a Software Architect for PBS. He is a Microsoft MVP.
This entry was posted in z Silverlight Archives. Bookmark the permalink.

One Response to RC0 & ContentPresenter

Comments are closed.