WPF 元素绑定结合值转换器的应用——室内监控可视化

需求

在物联网应用中,可视化端经常需要将实物信息详细的呈现到用户视野之中。在室内环境中,经常可见的设备空调和灯。本次课题主要以室内空调和灯监控出发,实现室内监控信息可视化。为了让可视化更加直观,我们需要完成的任务有:

1.用户操作开关之后,界面要同步运行状态。

2.美化界面,让信息状态变化直观的投射给用户。

首先上效果:

 

环境

Windows 10

Visual Studio 2019

.Net Framework 4.7.2

 

设计

UI设计:

功能设计:

当打开灯时:灯会亮起来(白色),关闭时暗下去(灰色)。

当打开空调时:空调量绿灯运行,同时吹风;关闭时绿灯消失,风停止。

通过属性绑定和值转换器实现以上功能。

 

实现

1.自定义抽象值转换器

using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Markup;

namespace Deamon.ValueConverters
{

    public abstract class BaseValueConverter<T> : MarkupExtension, IValueConverter
        where T : class, new()
    {
       
        private static T Converter = null;

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return Converter ?? (Converter = new T());
        }

        public abstract object Convert(object value, Type targetType, object parameter, CultureInfo culture);

        
        public abstract object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture);
    }
}

2.实现一个将Boolean值转换成Visibility值得转换器

using System;
using System.Globalization;
using System.Windows;

namespace Deamon.ValueConverters
{
    /// <summary>
    /// 一个转换器,将一个布尔值转换成 <see cref="Visibility"/> 类型
    /// 如果带有参数 parameter 则是 True 表示显示,FALSE 表示隐藏
    /// 如果不带参数 parameter 则是 True 表示隐藏,FALSE 表示显示
    /// 
    /// </summary>
    public class BooleanToVisibilityConverter : BaseValueConverter<BooleanToVisibilityConverter>
    {
        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (parameter == null)
                return (bool)value ? Visibility.Hidden : Visibility.Visible;
            else
                return (bool)value ? Visibility.Visible : Visibility.Hidden;
        }

        public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

3.设计XAML实现UI,使用元素绑定和值转换器实现界面刷新

<Window x:Class="Deamon.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Deamon"
        xmlns:converter="clr-namespace:Deamon.ValueConverters"
        mc:Ignorable="d"
        Title="房间信息实时监控" Height="450" Width="800">
    <Grid Background="#FF423E3E">

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="2*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <!-- 室内信息 -->
        <Grid Grid.Column="1">
            <Border Width="400" Height="400" BorderThickness="1" BorderBrush="Black" Background="#FF063463">
                <Grid>
                    <!-- 房间的边缘 -->
                    <Path Stroke="Black" StrokeThickness="2" Data="M1,1 1,50"/>
                    <Path Stroke="Black" StrokeThickness="20" Data="M10,160 10,240"/>
                    <Path Stroke="#FFB0ADAD" StrokeThickness="3" Data="M398,10 398,180"/>
                    <Path Stroke="#FFB0ADAD" StrokeThickness="3" Data="M398,220 398,390"/>

                    <!-- 默认静态灯 -->
                    <Border Padding="10" >
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="*"/>
                                <RowDefinition Height="*"/>
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="*"/>
                                <ColumnDefinition Width="*"/>
                            </Grid.ColumnDefinitions>
                            <Border x:Name="StaticLamb1" Background="Gray" Grid.Row="0" Grid.Column="0" BorderBrush="Black" BorderThickness="2" Width="30" Height="100"/>
                            <Border x:Name="StaticLamb2" Background="Gray" Grid.Row="0" Grid.Column="1"  BorderBrush="Black" BorderThickness="2" Width="30" Height="100"/>
                            <Border x:Name="StaticLamb3" Background="Gray" Grid.Row="1" Grid.Column="0" BorderBrush="Black" BorderThickness="2" Width="30" Height="100"/>
                            <Border x:Name="StaticLamb4" Background="Gray"  Grid.Row="1" Grid.Column="1" BorderBrush="Black" BorderThickness="2" Width="30" Height="100"/>
                        </Grid>
                    </Border>

                    <!-- 点亮的灯 -->
                    <Border Padding="10" >
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="*"/>
                                <RowDefinition Height="*"/>
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="*"/>
                                <ColumnDefinition Width="*"/>
                            </Grid.ColumnDefinitions>
                            <Border Grid.Row="0"  Grid.Column="0"
                                    Visibility="{Binding ElementName=ControlLamp12, Path=IsChecked,Converter={converter:BooleanToVisibilityConverter}, ConverterParameter=True}"
                                    Opacity="1">
                                <Border.Background>
                                    <RadialGradientBrush Center="0.7 0.5">
                                        <GradientStop Color="White" Offset="0"/>
                                        <GradientStop Color="#FF024391" Offset="1"/>
                                    </RadialGradientBrush>
                                </Border.Background>
                                <Border x:Name="Lamb1" 
                                    Background="White" BorderBrush="Black" BorderThickness="2" Width="30" Height="100">
                                    <Border.Effect>
                                        <DropShadowEffect BlurRadius="50" Opacity="1" ShadowDepth="0" Color="White"/>
                                    </Border.Effect>
                                </Border>
                            </Border>

                            <Border Grid.Row="0"  Grid.Column="1"
                                    Visibility="{Binding ElementName=ControlLamp12, Path=IsChecked,Converter={converter:BooleanToVisibilityConverter}, ConverterParameter=True}"
                                    Opacity="1">
                                <Border.Background>
                                    <RadialGradientBrush Center="0.3 0.5">
                                        <GradientStop Color="White" Offset="0"/>
                                        <GradientStop Color="#FF024391" Offset="1"/>
                                    </RadialGradientBrush>
                                </Border.Background>
                                <Border x:Name="Lamb2" 
                                Background="White"   BorderBrush="Black" BorderThickness="2" Width="30" Height="100">
                                    <Border.Effect>
                                        <DropShadowEffect BlurRadius="50" Opacity="1" ShadowDepth="0" Color="White"/>
                                    </Border.Effect>
                                </Border>
                            </Border>

                           
                            <Border Grid.Row="1" Grid.Column="0"
                                    Visibility="{Binding ElementName=ControlLamp34, Path=IsChecked,Converter={converter:BooleanToVisibilityConverter}, ConverterParameter=True}"
                                    Opacity="1">
                                <Border.Background>
                                    <RadialGradientBrush>
                                        <GradientStop Color="White" Offset="0"/>
                                        <GradientStop Color="#FF024391" Offset="1"/>
                                    </RadialGradientBrush>
                                </Border.Background>
                                <Border x:Name="Lamb3" 
                                Background="White"   BorderBrush="Black" BorderThickness="2" Width="30" Height="100">
                                    <Border.Effect>
                                        <DropShadowEffect BlurRadius="50" Opacity="1" ShadowDepth="0" Color="White"/>
                                    </Border.Effect>
                                </Border>
                            </Border>

                            <Border  Grid.Row="1" Grid.Column="1"
                                      Visibility="{Binding ElementName=ControlLamp34, Path=IsChecked,Converter={converter:BooleanToVisibilityConverter}, ConverterParameter=True}"
                                    Opacity="1">
                                <Border.Background>
                                    <RadialGradientBrush>
                                        <GradientStop Color="White" Offset="0"/>
                                        <GradientStop Color="#FF024391" Offset="1"/>
                                    </RadialGradientBrush>
                                </Border.Background>
                                <Border x:Name="Lamb4"
                                        Background="White"  BorderBrush="Black" BorderThickness="2" Width="30" Height="100">
                                    <Border.Effect>
                                        <DropShadowEffect BlurRadius="50" Opacity="1" ShadowDepth="0" Color="White"/>
                                    </Border.Effect>
                                </Border>
                            </Border>

                          


                        </Grid>

                    </Border>

                    <!-- 空调 -->
                    <Grid Width="60" Height="100" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="20 40 0 0" >
                        <Grid Width="40" HorizontalAlignment="Right" Opacity="1" 
                              Visibility="{Binding ElementName=ControlAirCondition,Path=IsChecked,Converter={converter:BooleanToVisibilityConverter},ConverterParameter=True}"
                              Margin="0 0 0 0">
                            <StackPanel x:Name="AirConditionWind" Width="40" VerticalAlignment="Center" Margin="0 0 0 0">
                                <StackPanel.Triggers>
                                    <EventTrigger RoutedEvent="Loaded">
                                        <BeginStoryboard>
                                            <Storyboard>
                                                <ThicknessAnimation Duration="00:00:04" RepeatBehavior="Forever" 
                                                                    Storyboard.TargetProperty="Margin"
                                                                    Storyboard.TargetName="AirConditionWind"
                                                                    To="20 0 0 0" From="0 0 0 0"/>
                                            </Storyboard>
                                        </BeginStoryboard>
                                    </EventTrigger>
                                </StackPanel.Triggers>
                                <Viewbox Height="20">
                                    <Path Stroke="White" StrokeThickness="10"  
                                          Data="M 10,100 C 100,0 200,200 300,100 M 300,100 C 400,0 500,200 600,100" />
                                </Viewbox>
                                <Viewbox Height="20">
                                    <Path Stroke="Red" StrokeThickness="10"  
                                          Data="M 10,100 C 100,0 200,200 300,100 M 300,100 C 400,0 500,200 600,100" />
                                </Viewbox>
                                <Viewbox Height="20">
                                    <Path Stroke="White" StrokeThickness="10"  
                                          Data="M 10,100 C 100,0 200,200 300,100 M 300,100 C 400,0 500,200 600,100" />
                                </Viewbox>
                                <Viewbox Height="20">
                                    <Path Stroke="White" StrokeThickness="10"  
                                          Data="M 10,100 C 100,0 200,200 300,100 M 300,100 C 400,0 500,200 600,100" />
                                </Viewbox>
                            </StackPanel>
                        </Grid>
                        <Border Visibility="Visible" HorizontalAlignment="Left" Width="40" Height="100" BorderBrush="Black" BorderThickness="1">
                            <Border.Background>
                                <LinearGradientBrush EndPoint="1,1" StartPoint="0,1">
                                    <GradientStop Color="#FF072442" Offset="0"/>
                                    <GradientStop Color="#FF213D5B" Offset="0.8"/>
                                    <GradientStop Color="#FF486683" Offset="1"/>
                                </LinearGradientBrush>
                            </Border.Background>
                            <Grid>
                                <Border BorderBrush="Black" BorderThickness="1" Margin="2" Width="4" HorizontalAlignment="Right"/>
                                <Rectangle Fill="Lime" 
                                           Width="15"
                                           Visibility="{Binding ElementName=ControlAirCondition,Path=IsChecked,Converter={converter:BooleanToVisibilityConverter},ConverterParameter=True}"
                                           Height="15"
                                           />
                            </Grid>
                        </Border>
                    </Grid>

                </Grid>
            </Border>

        </Grid>

        <!-- 显示控制板 -->
        <Border Grid.Column="2">
            <StackPanel VerticalAlignment="Center">
                <Border BorderBrush="AliceBlue" BorderThickness="1" Width="230" Margin="10" Padding="10" >
                    <StackPanel>
                        <Grid Margin="0 0 0 5">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="*"/>
                                <ColumnDefinition Width="50"/>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="20"/>
                            </Grid.ColumnDefinitions>
                            <TextBlock Grid.Column="0" Foreground="White" Text="一二号灯状态:" HorizontalAlignment="Right"/>
                            <TextBlock Grid.Column="1"
                                       Visibility="{Binding ElementName=ControlLamp12,Path=IsChecked,Converter={converter:BooleanToVisibilityConverter}}"
                                       Foreground="Orange" 
                                       Text="关闭"/>
                            <TextBlock Grid.Column="1" 
                                       Visibility="{Binding ElementName=ControlLamp12,Path=IsChecked,Converter={converter:BooleanToVisibilityConverter},ConverterParameter=True}"
                                       Foreground="Lime"
                                       Text="运行"/>

                            <CheckBox Grid.Column="2"
                                      x:Name="ControlLamp12" IsChecked="False" Content="开启" HorizontalAlignment="Center" Foreground="White"/>

                        </Grid>
                        <Grid Margin="0 5">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="*"/>
                                <ColumnDefinition Width="50"/>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="20"/>
                            </Grid.ColumnDefinitions>
                            <TextBlock Grid.Column="0" Foreground="White" Text="三四号灯状态:" HorizontalAlignment="Right"/>
                            <TextBlock Grid.Column="1" 
                                       Visibility="{Binding ElementName=ControlLamp34,Path=IsChecked,Converter={converter:BooleanToVisibilityConverter}}"
                                       Foreground="Orange" 
                                       Text="关闭"/>
                            <TextBlock Grid.Column="1" 
                                       Visibility="{Binding ElementName=ControlLamp34,Path=IsChecked,Converter={converter:BooleanToVisibilityConverter},ConverterParameter=True}"
                                       Foreground="Lime"
                                       Text="运行"/>
                            <CheckBox Grid.Column="2" x:Name="ControlLamp34" IsChecked="False" Content="开启" HorizontalAlignment="Center" Foreground="White"/>
                        </Grid>
                    </StackPanel>
                </Border>

                <Border BorderBrush="AliceBlue" BorderThickness="1" Width="230" Margin="10" Padding="10">
                    <StackPanel>
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="*"/>
                                <ColumnDefinition Width="50"/>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="20"/>
                            </Grid.ColumnDefinitions>
                            <TextBlock Grid.Column="0" Foreground="White" Text="空调运行状态:" HorizontalAlignment="Right"/>
                            <TextBlock Grid.Column="1" 
                                       Visibility="{Binding ElementName=ControlAirCondition,Path=IsChecked,Converter={converter:BooleanToVisibilityConverter}}"
                                       Foreground="Orange"
                                       Text="关闭"/>
                            <TextBlock Grid.Column="1" 
                                       Visibility="{Binding ElementName=ControlAirCondition,Path=IsChecked,Converter={converter:BooleanToVisibilityConverter},ConverterParameter=True}"
                                       Foreground="Lime"
                                       Text="运行"/>

                            <CheckBox  Grid.Column="2" x:Name="ControlAirCondition" VerticalAlignment="Center" IsChecked="False" Content="开启" 
                                  HorizontalAlignment="Center" Foreground="White">

                            </CheckBox>
                        </Grid>
                    </StackPanel>
                </Border>
            </StackPanel>
        </Border>

    </Grid>
</Window>

 

划重点

元素绑定:

Visibility="{Binding ElementName=ControlLamp12, Path=IsChecked,Converter={converter:BooleanToVisibilityConverter}, ConverterParameter=True}"

如上红字警告:如果是普通的元素绑定,红字基本就能表示(方法有很多哈,上面的不是唯一的)。但是,我们知道属性IsChecked bool类型的但是我们的属性Visibility却是Visibility的枚举值。因此,我们需要后面Converter来实现属性值之间的转换。

值转换器:

Visibility="{Binding ElementName=ControlLamp12, Path=IsChecked,Converter={converter:BooleanToVisibilityConverter}, ConverterParameter=True}"

解析下:红字表示属性Visibility的Converter转换器是使用的{converter:BooleanToVisibilityConverter}这个转换器,其中是converter名字空间,在文件头可以看到 xmlns:converter="clr-namespace:Deamon.ValueConverters" 。后面的ConverterParameter=True 表示传递的参数,具体信息在BooleanToVisibilityConverter转换器类中有详细说明。

 

Over

每次记录一小步...点点滴滴人生路...

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值