65.9K
CodeProject 正在变化。 阅读更多。
Home

在最小值和最大值之间进行缩放(视觉效果)(例如,等级条)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.82/5 (3投票s)

2009年3月11日

GPL3

2分钟阅读

viewsIcon

32362

downloadIcon

504

如果你需要某种等级条/仪表,请看一看!

MinMaxScaling

引言

在许多与过程自动化相关的项目中,需要以视觉方式显示设备和当前状态。 许多设备,例如储罐,都有某种仪表,应该显示范围内的当前值(最小值/最大值)。 让我们看看如何使用 WPF Viewbox 和一些简单的计算以动态方式实现这一点。

结构

对于这个例子,我使用了以下结构

  • 上面看到的图像是一个渲染后的 WPF UserControl,应该代表一个储罐。 它执行以下操作
    • 它具有用于最小值和最大值参数以及当前液位的代码隐藏属性。
    • 还有一个属性,将当前液位从最小值/最大值缩放到 0/1(即 0...100%)。
  • 该控件在应用程序的主窗口中多次实例化。

设备用户控件

首先,让我们看一下 XAML

<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>

很简单!

在“输入数据部分”,我们只是将一些文本框绑定到控件的 MinMaxCurrentLevel 属性,以便我们可以玩弄这些值并查看会发生什么。

让我们看看“液位部分”中会发生什么:这里,我们有一个边框,它是其父级 DockPanel 的最后一个元素,这意味着该边框完全填充了 DockPanel 的剩余空间。 在边框内部,我们有一个 Viewbox,应该将其内容拉伸以填充剩余空间(换句话说,Viewbox 的内容应该覆盖我们的 UserControl 的完整剩余空间)。

我们想要实现的是液位表具有深灰色背景(来自边框),然后有一个蓝色条显示缩放后的值。

Mechanism.png

诀窍是在 Viewbox 内部将所有内容限制为 1(HeightWidth),以便在 Viewbox 内部具有“逻辑”或“标准化”大小。 有一个不可见的 Rectangle,其 Height = 1,用于限制高度,以及我们的蓝色液位 Rectangle,其 Width = 1(用于限制宽度)。 然后,Viewbox 将所有内容缩放到“真实”大小。

剩下的唯一问题是用户控件的代码隐藏中的缩放。

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;
    }
}

请注意,每次 MinMaxCurrentLevel 发生变化时,我们还会通知 ScaledValue 发生了变化,因为该属性取决于这些属性。 在数学上,我们从 Min / Max 归一化到 0 / 1

Math.png

就是这样!

© . All rights reserved.