Zoom on a graph with XAML code in C#


Zoom on a graph with XAML code

This example shows how you can zoom on a graph with XAML code only, without using C# code. (The program does use C# code to build the graph. It just doesn’t use any to zoom.)

The example Zoom in on a graph in WPF and C# lets you use a Slider to zoom in and out on a graph. When you adjust the Slider, its ValueChanged event handler displays the zoom factor in a Label and scales the Canvas containing the graph. This example uses XAML code to perform the necessary updates when you change the Slider value.

To modify the previous example, first remove the Slider control’s ValueChanged event handler from the C# code, and remove the ValueChanged property from the Slider in the XAML code.

Next add XAML code to update the Label and set the Canvas control’s LayoutTransform property. The following shows the program’s XAML code with the most important changes highlighted in blue.

<Window x:Class="howto_xaml_scaled_graph.Window1"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   Title="howto_xaml_scaled_graph"
   Height="300" Width="480" Loaded="Window_Loaded">
   <Grid Background="LightGreen">
      <Grid.RowDefinitions>
         <RowDefinition Height="30"/>
         <RowDefinition Height="*"/>
      </Grid.RowDefinitions>
      <Grid.ColumnDefinitions>
         <ColumnDefinition Width="50"/>
         <ColumnDefinition Width="*"/>
      </Grid.ColumnDefinitions>

      <!-- The following doesn't work with a Label -->
      <TextBlock Grid.Row="0" Grid.Column="0"
         Text="{Binding ElementName=sliZoom, Path=Value, StringFormat='\{0:P0\}'}"
         HorizontalAlignment="Center"
         VerticalAlignment="Center"/>
      <Slider Name="sliZoom" Orientation="Vertical"
         HorizontalAlignment="Center"
         Margin="0,0,0,5"
         Grid.Row="1" Grid.Column="0"
         Minimum="0.25" Maximum="3.00" Value="1.00"
         SmallChange="0.25" LargeChange="0.25"
         TickFrequency="0.25" TickPlacement="BottomRight"
         IsSnapToTickEnabled="True"/>

      <ScrollViewer Name="scvGraph"
         Grid.Row="0" Grid.Column="1" Grid.RowSpan="2"
         HorizontalScrollBarVisibility="Auto"
         VerticalScrollBarVisibility="Auto">
         <Canvas Name="canGraph" Background="White"
            MouseMove="canGraph_MouseMove"
            MouseUp="canGraph_MouseUp"
            Width="400" Height="250"
            VerticalAlignment="Center"
            HorizontalAlignment="Center">
            <Canvas.LayoutTransform>
               <ScaleTransform
                  ScaleX="{Binding ElementName=sliZoom, Path=Value}"
                  ScaleY="{Binding ElementName=sliZoom, Path=Value}"/>
            </Canvas.LayoutTransform>
         </Canvas>
      </ScrollViewer>
   </Grid>
</Window>

The first change is that the Label in the previous example was changed into a TextBlock because the same binding technique didn’t work on a Label. (Perhaps it has something to do with the fact that a Label control’s Content property can hold just about anything and not just text. The TextBlock control’s Text property can only hold text.)

Notice that the TextBlock control’s Text property is set to:

"{Binding ElementName=sliZoom, Path=Value, StringFormat='\{0:P0\}'}"

This tells the control to bind its Text property to the Value property of the element (control) named sliZoom. The result should be displayed using the formatting string {0:P0}. That string means the argument number 0 (that’s what the first 0 means) should be formatted as a percentage (that’s what the P means) with no digits of precision after the decimal point (that’s what the 0 after the P means). Note that there is only one argument to pass into the formatter (the bound value), so it wouldn’t make sense to use any other argument number than 0.

The next change is to the Slider control’s value-related properties. Let me skip those changes for now and first describe the change to the Canvas control. The new program gives it a LayoutTransform property set equal to a ScaleTransform. The Scaletransform object’s ScaleX and ScaleY properties are each set to:

"{Binding ElementName=sliZoom, Path=Value}"

This makes those properties take the value in the sliZoom control’s Value property.

Now when you adjust the Slider control’s value, the TextBlock and ScaleTransform automatically update themselves.

The last change, which I skipped earlier, was to the Slider control’s value-related properties Minimum, Maximum, Value, SmallChange, LargeChange, and TicFrequency.

In the previous example, those values were integers between 25 and 200. They represented the zoom factor as a percentage. The C# code in the ValueChanged event handler displayed them (with % added). It then divided them by 100 and used them to make the necessary ScaleTransform.

Unfortunately XAML doesn’t have any way to perform mathematical operations such as dividing by 100. That’s why this example makes these values between 0.25 and 2.00. The P in the format string automatically multiplies the value by 100 and appends a % symbol. The ScaleTransform uses the values as they are. In this way, both parts of the program can use the same value.


Download Example   Follow me on Twitter   RSS feed




About RodStephens

Rod Stephens is a software consultant and author who has written more than 30 books and 250 magazine articles covering C#, Visual Basic, Visual Basic for Applications, Delphi, and Java.

This entry was posted in algorithms, drawing, geometry, graphics, mathematics and tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *