Click here to Skip to main content
15,880,608 members
Articles / Desktop Programming / WPF

Scaling (visual) between a min and max value (e.g., level bar)

Rate me:
Please Sign up or sign in to vote.
4.82/5 (3 votes)
9 Apr 2010GPL32 min read 31.7K   487   18   3
If you need some kind of level bar / meter, take a look!
MinMaxScaling

Introduction

In many projects that are related to process automation, it is necessary to display equipments and the current state in a visual representation. Many equipments, for example, a tank, have some kind of meter that should display a current value between a range (min / max). Let's have a look at how we can do that in a dynamic way using the WPF Viewbox and some simple calculations.

Structure

For this example, I used the following structure:

  • The image we see above is a rendered WPF UserControl that should represent a tank. It does the following:
    • It has code-behind properties for min and max parameters and for the current level.
    • There is also a property that scales the current level from min / max to 0 / 1 (so 0...100%).
  • The control is instantiated several times in the main window of the application.

The Equipment User Control

First, let's have a look at the XAML:

XML
<UserControl x:Class="Technewlogic.Samples.MinMaxScaling.Equipment"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:converter="clr-namespace:Technewlogic.Samples.MinMaxScaling"
    x:Name="me">

<Grid Margin="5" DataContext="{Binding ElementName=me}">
    <Rectangle x:Name="backgroundRect" Fill="LightGray" 
      Stroke="DarkGray" StrokeThickness="2" 
      RadiusX="5" RadiusY="5" />
    
    <DockPanel LastChildFill="True" Margin="5">
        
        <!-- Enter Data Section -->
        <Grid Margin="3" DockPanel.Dock="Left">
            <StackPanel Orientation="Horizontal" 
                       VerticalAlignment="Top" 
                       HorizontalAlignment="Right">
                <TextBlock Text="Max Level:" Margin="2" 
                       VerticalAlignment="Center" />
                <TextBox Text="{Binding Max, UpdateSourceTrigger=PropertyChanged}" 
                       Width="30" Margin="2" />
            </StackPanel>
            <StackPanel Orientation="Horizontal" 
                   VerticalAlignment="Center" 
                   HorizontalAlignment="Right">
                <TextBlock Text="Current Level:" FontWeight="Bold" 
                   Margin="2" VerticalAlignment="Center" />
                <TextBox Text="{Binding CurrentLevel, 
				UpdateSourceTrigger=PropertyChanged}" 
                         Width="30" Margin="2" />
            </StackPanel>
            <StackPanel Orientation="Horizontal" VerticalAlignment="Bottom" 
                          HorizontalAlignment="Right">
                <TextBlock Text="Min Level:" Margin="2" 
                          VerticalAlignment="Center" />
                <TextBox Text="{Binding Min, UpdateSourceTrigger=PropertyChanged}" 
                          Width="30" Margin="2" />
            </StackPanel>
        </Grid>

        <!-- Level Section -->

        <Border x:Name="LevelSection" CornerRadius="3" 
                   BorderBrush="DarkGray" Background="Gray" 
                   BorderThickness="1" Margin="3">
            <Viewbox Stretch="Fill">
                <StackPanel Orientation="Horizontal">
                    <Rectangle Fill="Red" Height="1" Width="0" />
                    <Rectangle Fill="Blue" Width="1" 
                            VerticalAlignment="Bottom" Height="{Binding ScaledValue}" />
                </StackPanel>
            </Viewbox>
        </Border>
    </DockPanel>
</Grid>
</UserControl>

Quite simple!

In the "Enter Data Section", we just bind some textboxes to the Min, Max, and CurrentLevel properties of our control, so that we can play a little bit with the values and see what happens.

Let's have a look at what happens in the "Level Section": here, we have a border that is the last element of its parent DockPanel, so this means that the border completely fills the remaining space of the DockPanel. Inside the border, we have a Viewbox that should stretch its content to fill the remaining space (in other words, the content of the Viewbox should cover the complete remaining space of our UserControl).

What we want to achieve is that the level meter has a Dark Gray background (coming from the border) and then have a blue bar showing the scaled value.

Mechanism.png

The trick is that inside the Viewbox, we "limit" everything to 1 (Height and Width) to have a "logical" or "normalized" size inside the Viewbox. There is an invisible Rectangle with Height = 1 to limit the height, and our blue level Rectangle with Width = 1 (to limit the width). The Viewbox then scales everything to "real" size.

The only thing left open is the scaling in the code-behind of our UserControl.

C#
private double _min = 0d;
public double Min
{
    get { return _min; }
    set
    {
        _min = value;
        OnPropertyChanged("Min");
        OnPropertyChanged("ScaledValue");
    }
}

private double _max = 100d;
public double Max
{
    get { return _max; }
    set
    {
        _max = value;
        OnPropertyChanged("Max");
        OnPropertyChanged("ScaledValue");
    }
}

private double _currentLevel = default(double);
public double CurrentLevel
{
    get { return _currentLevel; }
    set
    {
        _currentLevel = value;
        OnPropertyChanged("CurrentLevel");
        OnPropertyChanged("ScaledValue");
    }
}

public double ScaledValue
{
    get
    {
        var scaledValue = CurrentLevel / (Max - Min) - (Min / (Max - Min));
        return scaledValue;
    }
}

Notice that on each change of Min, Max, or CurrentLevel, we also notify that the ScaledValue has changed, because this property depends on those. Mathematically, we normalize from Min / Max to 0 / 1:

Math.png

That's it!

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Software Developer (Senior) www.technewlogic.de
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionUsing Scaling UserControl with Entity Framework and MVVM Pin
tvi71it8-Apr-10 22:38
tvi71it8-Apr-10 22:38 
AnswerRe: Using Scaling UserControl with Entity Framework and MVVM Pin
Ronald Schlenker8-Apr-10 23:58
Ronald Schlenker8-Apr-10 23:58 
GeneralRe: Using Scaling UserControl with Entity Framework and MVVM Pin
tvi71it9-Apr-10 5:23
tvi71it9-Apr-10 5:23 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.