Reader Level:
ARTICLE

How to Handle Manipulation Events and Properties in Windows Phone 7

Posted by Charles Petzold Articles | Windows Phone December 02, 2010
This article describes common elements and some important properties you can apply to all these elements, including transforms. This lays the groundwork for the subject of Panel elements that provide the basis of Silverlight’s dynamic layout system.
  • 0
  • 0
  • 6851

This chapter is taken from book "Programming Windows Phone 7" by Charles Petzold published by Microsoft press. http://www.charlespetzold.com/phone/index.html

Handling Manipulation Events: Transforms are also a good way to handle manipulation events. Here's a ball sitting in the middle of the content grid:

        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <Ellipse Width="200"
                        Height="200"
                        RenderTransformOrigin="0.5 0.5"
                        ManipulationDelta
="OnEllipseManipulationDelta">
                <Ellipse.Fill>
                    <RadialGradientBrush Center="0.4 0.4"
                                            GradientOrigin="0.4 0.4">
                        <GradientStop Offset="0" Color="White" />
                        <GradientStop Offset="1" Color="{StaticResource PhoneAccentColor}" />
                    </RadialGradientBrush>
                </Ellipse.Fill>               
               
<Ellipse.RenderTransform>
                    <CompositeTransform  />
                </Ellipse.RenderTransform>
            </Ellipse>
        </Grid>

Notice the CompositeTransform. It has no name so the code will have to reference it through the Ellipse element. (This is a good strategy to use if you're handling more than one element in a single event handler.)

The code-behind file just handles the ManipulationDelta event from the Ellipse:

namespace DragAndScale
{
    public partialclass MainPage : PhoneApplicationPage
    {
        public MainPage()
        {
            InitializeComponent();
        }
          
void OnEllipseManipulationDelta(object sender,ManipulationDeltaEventArgs args)
        {
            Ellipse ellipse = senderas Ellipse;
            CompositeTransform xform = ellipse.RenderTransform asCompositeTransform;
 
            if (args.DeltaManipulation.Scale.X > 0 || args.DeltaManipulation.Scale.Y > 0)
            {
                double maxScale =Math.Max(args.DeltaManipulation.Scale.X,
                                           args.DeltaManipulation.Scale.Y);
                xform.ScaleX *= maxScale;
                xform.ScaleY *= maxScale;
            } 
            xform.TranslateX += args.DeltaManipulation.Translation.X;
            xform.TranslateY += args.DeltaManipulation.Translation.Y;
            args.Handled = true;
        }
    }
}

For handling anything other than taps, the ManipulationDelta event is crucial. This is the event that consolidates one or more fingers on an element into translation and scaling information.

The Border Element

The TextBlockdoesn't include any kind of border that you can draw around the text. Fortunately Silverlight has a Border element that you can use to enclose a TextBlock or any other type of element. The Border has a property named Child of type UIElement, which means you can only put one element in a Border; however, the element you put in the Border can be a panel, and you can then add multiple elements to that panel.

You can center the TextBlock within the Border:

        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <Border Background="Navy"
                    BorderBrush="Blue"
                    BorderThickness
="16"
                    CornerRadius="25">
                <TextBlock Text="Hello, Windows Phone 7!"
                           HorizontalAlignment="Center"
                           VerticalAlignment="Center" />
            </Border>
        </Grid>

Or, you can center the Border within the Grid:

        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <Border Background="Navy"
                    BorderBrush="Blue"
                    BorderThickness="16"
                    CornerRadius="25"
                    HorizontalAlignment="Center"
                    VerticalAlignment="Center">
                <TextBlock Text="Hello, Windows Phone 7!" />
            </Border>
        </Grid>

At this point, the Border contracts in size to become only large enough to fit the TextBlock. You can also set the HorizontalAlignment and VerticalAlignment properties of the TextBlock but they would now have no effect. You can give the TextBlock a little breathing room inside the border by either setting the Margin or Padding property of the TextBlock, or the Padding property of the Border:

e1.gif

And now we have an attractive Border surrounding the TextBlock. The BorderThickness property is of type Thickness, the same structure used for Margin or Padding, so you can potentially have four different thicknesses for the four sides. The CornerRadius property is of type CornerRadius, a structure that also lets you specify four different values for the four corners. The Background and BorderBrush properties are of type Brush, so you can use gradient brushes.

If you want a Border with a "normal" thickness, you can use one of the pre-defined resources:

        <Border BorderThickness="{StaticResource PhoneBorderThickness}"

This is 3 pixels in width. The PhoneStrokeThickness resource also provides that same value.

What happens if you set a RenderTransform on the TextBlock? Try this:

        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <Border Background="Navy"
                    BorderBrush="Blue"
                    BorderThickness="16"
                    CornerRadius="25"
                    HorizontalAlignment="Center"
                    VerticalAlignment="Center"
                    Padding="20">
                <TextBlock Text="Hello, Windows Phone 7!" RenderTransformOrigin="0.5 0.5">
               
    <TextBlock.RenderTransform>
                       
<RotateTransform Angle="45" />
                    </
TextBlock.RenderTransform>
                </
TextBlock>
            </Border>
        </Grid>

Here's what you get:

e2.gif

The RenderTransform property is called a render transform for a reason: It only affects rendering. It does not affect how the element is perceived in the layout system. Your spirits might perk up, however, when you try moving the RenderTransform (and RenderTransformOrigin) from the TextBlock to the Border, like this:

        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
           
<Border Background="Navy"
                    BorderBrush="Blue"
                    BorderThickness="16"
                    CornerRadius="25"
                    HorizontalAlignment="Center"
                    VerticalAlignment="Center"
                    Padding="20"
                    RenderTransformOrigin="0.5 0.5">
                <Border.RenderTransform>
                    <RotateTransform Angle="45" />
                </Border.RenderTransform>
                <TextBlock Text="Hello, Windows Phone 7!" />
            </Border>
        </Grid>

Transforms affect not only the element to which they are applied, but all child elements as this screen shot makes clear:

e3.gif

TextBlock Properties and Inlines

The TextBlock element has five font-related properties: FontFamily, FontSize, FontStretch, FontStyle, and FontWeight, TextBlock also has a TextDecorations property. Although this property seems to be very generalized.

However, you might be surprised to learn that the ContentProperty attribute of TextBlock is not the Text property but an entirely different property named Inlines. This Inlines property is of type InlineCollection-a collection of objects of type Inline, namely LineBreak and Run. These make TextBlock much more versatile. Run is interesting because it too has FontFamily, FontSize, FontStretch, FontStyle, FontWeight, Foreground, and TextDecorations properties, so you can make your text very fancy:

<TextBlock FontSize="36"
           TextWrapping="Wrap">
    This is
    some
<Run FontWeight="Bold">bold</Run> text and
    some
<Run FontStyle="Italic">italic</Run> text and
    some
<Run Foreground="Red">red</Run> text and
    some
<Run TextDecorations="Underline">underlined</Run> text
    and some
<Run FontWeight="Bold"
                  FontStyle="Italic"
                  Foreground="Cyan"
                  FontSize="72"
                  TextDecorations="Underline">big</Run> text.
</TextBlock>

In the Visual Studio design view, you might see the text within the Run tags not properly separated from the text outside the Run tags. This is an error. When you actually run the program in the emulator, it looks fine:

e4.gif

The FontFamilies program lists all the FontFamily values that Visual Studio's Intellisense tells us are valid:

        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <TextBlock FontSize="24">
                <Run FontFamily="Arial">Arial</Run><LineBreak />
                <Run FontFamily="Arial Black">Arial Black</Run><LineBreak />
                <Run FontFamily="Calibri">Calibri</Run><LineBreak />
                <Run FontFamily="Comic Sans MS">Comic Sans MS</Run><LineBreak />
                <Run FontFamily="Courier New">Courier New</Run><LineBreak />
                <Run FontFamily="Georgia">Georgia</Run><LineBreak />
                <Run FontFamily="Lucida Sans Unicode">Lucida Sans Unicode</Run><LineBreak />
                <Run FontFamily="Portable User Interface">Portable User Interface</Run><LineBreak />
                <Run FontFamily="Segoe WP">Segoe WP</Run><LineBreak />
                <Run FontFamily="Segoe WP Black">Segoe WP Black</Run><LineBreak />
                <Run FontFamily="Segoe WP Bold">Segoe WP Bold</Run><LineBreak />
                <Run FontFamily="Segoe WP Light">Segoe WP Light</Run><LineBreak />
                <Run FontFamily="Segoe WP Semibold">Segoe WP Semibold</Run><LineBreak />
                <Run FontFamily="Segoe WP SemiLight">Segoe WP SemiLight</Run><LineBreak />
                <Run FontFamily="Tahoma">Tahoma</Run><LineBreak />
                <Run FontFamily="Times New Roman">Times New Roman</Run><LineBreak />
                <Run FontFamily="Trebuchet MS">Trebuchet MS</Run><LineBreak />
                <Run FontFamily="Verdana">Verdana</Run><LineBreak />
                <Run FontFamily="Webdings">Webdings</Run> (Webdings)
           
</TextBlock>
        </Grid>

Here's the result:

e5.gif

More on Images

The ImageExperiment project contains a folder named Images containing a file named BuzzAldrinOnTheMoon.png, which is the famous photograph taken with a Hasselblad camera by Neil Armstrong on July 21 st  1969. The photo is 288 pixels square. The file is referenced in the MainPage.xaml file like this:

        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"
              Background="{StaticResource PhoneAccentBrush}">
            <Image Source="Images/BuzzAldrinOnTheMoon.png" />
        </Grid>

I've also give the content grid a Background brush of the accent color just to make the photo stand out a little better. Here's how it appears in landscape mode: By

e6.gif

You can set transforms on the Image element with the same ease that you set them on TextBlock elements:

        <Image Source="Images/BuzzAldrinOnTheMoon.png" RenderTransformOrigin="0.5 0.5">
            <Image.RenderTransform>
                <RotateTransform Angle="30" />
           
</Image.RenderTransform>
        </Image>

Here it is:

e7.gif

Modes of Opacity

UIElement defines an Opacity property that you can set to a value between 0 and 1 to make an element (and its children) more or less transparent. But a somewhat more interesting property is OpacityMask, which can "fade out" part of an element.

For example, you can apply a RadialGradientBrush to the OpacityMask property of an Image element:

        <Image Source="Images/BuzzAldrinOnTheMoon.png">
            <Image.OpacityMask>
                <RadialGradientBrush>
                    <GradientStop Offset="0" Color="White" />
                    <GradientStop Offset="0.8" Color="White" />
                    <GradientStop Offset="1" Color="Transparent" />
                </RadialGradientBrush>
            </Image.OpacityMask>
        </Image>

Notice that the RadialGradientBrush is opaque in the center, and continues to be opaque until a radius of 0.8, at which point the gradient goes to fully transparent at the edge of the circle. Here's the result, a very nice effect that looks much fancier than the few lines of XAML would seem to imply:

e8.gif

COMMENT USING

Trending up