Introduction

This article is the first of a series that will try to present my implementation of some custom gauge controls for WP7. This first article will present some implementation considerations and the way to use the controls. The next articles will go deeper into the problem and will try to explain the implementation of these controls.

Implementation considerations

In my opinion, a gauge should present a scale and permit multiple indicators to point to particular values within that scale. When I say “scale”, I mean everything a gauge should contain except for the indicators. This means that in my opinion, a scale should contain ticks (minor and major), labels, and ranges. I use ranges to assign different colors to different intervals in the scale. These ranges can be used to indicate below optimal, optimal, or above optimal values.

In general terms, a scale should present the user with the following properties:

  • Minimum value – the minimum value in the scale. Indicators cannot point below this value.
  • Maximum value – the maximum value in the scale. Indicators cannot point above this value.
  • Minor tick step – small ticks will be placed at values that are multiples of the step, starting from but not including the minimum value. For example, small ticks will be placed at minimum + step, minimum + 2*step, etc.
  • Major tick step – big ticks will be placed at values that are multiples of the step, starting from the minimum value inclusively. For example, big ticks will be placed at minimum, minimum + step, etc. When the current value is a candidate for both small and big ticks, the big ticks will take precedence.
  • Ranges – these will indicate optimal ranges on the scale. For example, in a scale from 0 to 100, the user might specify that values below 50 are optimal values.
  • RangeThickness – specifies how thick the ranges should be.
  • UseDefaultRange – specifies whether or not to use a default range. This will have the effect of drawing a line below the ticks.
  • UseRangeColorsForTicks – specifies whether or not to use range colors for the ticks that are in a particular range (will not be implemented at this time).
  • Indicators – this collection will hold all the indicators for the particular scale.
  • Minor tick template, major tick template, and label template – these properties specify the templates that will be used when displaying the ticks and the labels.

There are two kinds of scales: linear scales and radial scales. Each one of these will have additional properties that will be added to the ones mentioned above. This article will present implementations for both kinds of scales.

Linear scales

For linear scales, we will have the following additional properties:

  • Orientation – specifies whether the scale is horizontal or vertical.
  • Linear tick placement – specifies the tick placement on the scale. Here, the ticks can be above the indicators or below them for horizontal scales, or they can be to the left or to the right of the indicators for vertical scales.

Radial scales

For radial scales, we will have the following additional properties:

  • Minimum angle – specifies the minimum angle from which the rotation starts.
  • Maximum angle – specifies the maximum angle where the rotation stops.
  • Sweep direction – specifies the rotation direction.
  • Radial tick placement – specifies the placement of the ticks. The ticks can be positioned inward or outward.
  • Radial type – concerning radial scales, there is an additional problem. We can have a full circle scale, a semicircle scale, or a quadrant scale. This option can be mainly used to save space on the screen. For example, if the user chooses a 90 degree range, maybe he doesn’t want to waste the other three quadrants of the circle. To save space, he can specify that he wants a quadrant. This property will be used in conjunction with the min, max angle and the sweep direction properties. This property will have an effect on the position of the center of rotation inside the area of the scale and on the range. If the angles and sweep direction don’t match, the user can choose to change them to get what he wants. This is easier than implementing complicated logic to determine the quadrant in code and coercing the angle values.

As you can see from the above properties, I have chosen to implement the tick placement in the derived classes. This is in order to further clarify the meaning of the properties. A single property in the base class with more options would have confused the user.

The image below presents the class hierarchy for the scale controls:

In the image above, you can see that the base class is abstract and that it is a Panel. The user can only instantiate derived instances.

Indicators

There can be quite a few kinds of indicators for both types of scales. We can have bar indicators (for both linear and radial scales), arrow indicators (for linear scales), marker indicators (for both linear and radial scales), or needle indicators (for radial scales). Indicators have a single custom property: the value property.

Bar indicators have two additional properties: bar thickness and bar brush. Marker indicators have one additional property: marker template.

The class hierarchy for the indicators can be seen in the image below:

Using the code

The scales and indicators are very easy to use. The first step is to add a reference to the assembly that contains the scales and reference that assembly in the page file to which you want to add the controls. Here is the assembly reference string:

xmlns:scada="clr-namespace:WPScadaControlsV2;assembly=WPScadaControlsV2"

After this, you can instantiate a scale in your page. The XAML below presents a two-row grid. Each row contains a scale. The top row contains a radial scale while the bottom row contains a linear scale.

<Grid x:Name="ContentGrid" Grid.Row="1" Margin="5" >
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <scada:RadialScale></scada:RadialScale>
    <scada:LinearScale Grid.Row="1"/>
</Grid>

The effect this code has can be seen in the image below.

As you can see from the image above, with very little code, you can get some very nice gauges. This is the default behavior for the two types of scales. In the following sections, I will talk about the customization options.

Setting the tick steps and templates

There are six properties that you can use to customize the ticks. These are: MinorTickStep, MajorTickStep, MinorTickTemplate, MajorTickTemplate, LabelTemplate, and TickPlacement. The last property (TickPlacement) is implemented in the derived scale classes. We can have a linear or a radial tick placement. The XAML below presents a way to modify the number of ticks that are shown on a scale.

<scada:RadialScale MinorTickStep="10" MajorTickStep="20"></scada:RadialScale>
<scada:LinearScale Grid.Row="1" MinorTickStep="5" MajorTickStep="25"/>

The effect this code has can be seen below:

To change the templates, you can use the three template related properties. The XAML below presents such an example.

<scada:RadialScale.MinorTickTemplate>
    <DataTemplate>
        <Rectangle Fill="Green" Width="5" Height="10"/>
    </DataTemplate>
</scada:RadialScale.MinorTickTemplate>
<scada:RadialScale.MajorTickTemplate>
    <DataTemplate>
        <Path Data="M0,0 L10,0 L5,20 Z" Fill="Purple"/>
    </DataTemplate>
</scada:RadialScale.MajorTickTemplate>
<scada:RadialScale.LabelTemplate>
    <DataTemplate>
        <TextBlock Text="{Binding}" FontWeight="Bold"
                   Foreground="Red"/>
    </DataTemplate>
</scada:RadialScale.LabelTemplate>

The effect of applying these templates to both scales can be seen in the image below.

The last tick related property is the TickPlacement. For the controls in the image above, the tick orientation is set to the default values. There are Outward for radial scales and TopLeft for linear scales.

The image below presents the same controls with the TickPlacement properties set to Inward (for the radial scale) and BottomRight (for the linear scale).

Working with ranges

The scales also give the user the possibility to add ranges. The ranges could represent optimal ranges. All the images you have seen so far have used a default range. The use of this default range can be selected by using the UseDefaultRange boolean property. If we set this to false for both the controls in the previous image, we get the result that can be seen in the image below.

Besides this default range, the user can add additional ranges by using the Ranges property. The XAML below shows a collection of three ranges. For each range, the user can set the color and the maximum value. Also, the user can set the RangeThickness property of the scale to control how thick the ranges should be.

<scada:RadialScale.Ranges>
    <scada:GaugeRange Color="Green" Offset="30"/>
    <scada:GaugeRange Color="Orange" Offset="60"/>
    <scada:GaugeRange Color="Red" Offset="100"/>
</scada:RadialScale.Ranges>

The result can be seen in the image below. In this case, the range thickness has been set to 5.

The image below presents the same settings, but this time with the TickPlacement property set to Inward.

Min angles, Max angles, and SweepDirection

Another set of properties that will help you customize the radial controls are the minimum and maximum angles and the sweep direction. These properties do exactly what their names suggest: they define the arc that will be used to draw the ticks and ranges. Some examples can be seen in the image below.

Radial type

The last property that can be used to customize the radial gauges is the RadialType property. Like I said earlier in the article, this property can be used to minimize the space used by radial gauges when the angle span is within certain intervals. For example, if the angle span is below 90 degrees, you could use a RadialType of Quarter to only occupy a quadrant of the entire circle. The same happens with semi circles. This property will check the min angle, max angle, and sweep direction properties to calculate the best layout of the control. Some examples that illustrate the use of this property can be seen below.

Adding indicators

The first set of indicators that I am going to present are the bar indicators. These indicators can be added to both radial and linear scales. The XAML below presents bar indicators for both scale types:

<scada:RadialBarIndicator Value="{Binding ElementName=slider, Path=Value}" 
       BarThickness="20" BarBrush="{StaticResource PhoneAccentBrush}" />

<scada:LinearBarIndicator Value="{Binding ElementName=slider, Path=Value}"
       BarThickness="10" BarBrush="{StaticResource PhoneAccentBrush}"/>

There is still a bug in the controls that only shows the radial bar indicator only if the value is obtained via data binding. I hope I will fix this soon. The effect of adding the indicators presented in the XAML above can be seen in the image below.

The last indicator I implemented is a needle indicator. This is used the same as the others. The image below presents a needle indicator.

Final thoughts

There are still a lot of bugs in the code, but I thought it will be better to present a high overview of the gauges first and fix the bugs as I write the other articles as opposed to waiting until everything is ready.

The following articles will present the implementation of these scales and indicators. Please feel free to post your suggestions or bug fixes (which will be very much appreciated:)).

History

  • Created on Monday, March 07, 2011.
推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架
新浪微博粉丝精灵,刷粉丝、刷评论、刷转发、企业商家微博营销必备工具"