zoukankan      html  css  js  c++  java
  • Silverlight自定义控件开发:温度计

    由于在实际项目中需要实时显示采集到的空气温湿度,土壤温湿度值,需要用比较显眼并且清楚明了的方式来展示,这里我们准备采用温度计的方式来进行。一方面是因为大家都熟悉这个,知道怎么去看;同时,温度计本身也比较好封装。以下就是封装好的效果及其调用代码(水银柱和刻度线都是有动画效果的,看上去比较逼真):

    image

    调用代码如下:

       1:              var data = new DataNotify();
       2:              data.MaxData = 30;
       3:              data.MinData = -15;
       4:   
       5:              data.MinRange = -15;
       6:              data.MaxRange = 75;
       7:   
       8:              data.CurrentData = 40;
       9:   
      10:              data.Title = "空气温度";
      11:              data.Unit = "℃";
      12:              data.ThemeSet = Theme.Red;
      13:   
      14:              var uc = new TemperatureControl(data);
      15:              uc.Margin = new Thickness(-620, 0, 10, 10);
      16:              Test.Children.Add(uc);
      17:   
      18:   
      19:              var data1 = new DataNotify();
      20:              data1.MaxData = 100;
      21:              data1.MinData = 0;
      22:              data1.MinRange = 0;
      23:              data1.MaxRange = 100;
      24:              data1.CurrentData = 83;
      25:              data1.Title = "空气湿度";
      26:              data1.Unit = "%";
      27:              data1.ThemeSet = Theme.Blue;
      28:   
      29:              var uc1 = new TemperatureControl(data1);
      30:              uc1.Margin = new Thickness(-207, 0, 10, 10);
      31:              Test.Children.Add(uc1);
      32:   
      33:              var data2 = new DataNotify();
      34:              data2.MaxData = 60;
      35:              data2.MinData = -10;
      36:              data2.MinRange = -10;
      37:              data2.MaxRange = 100;
      38:              data2.CurrentData = 36;
      39:              data2.Title = "土壤温度";
      40:              data2.Unit = "℃";
      41:              data2.ThemeSet = Theme.Orange;
      42:   
      43:              var uc2 = new TemperatureControl(data2);
      44:              uc2.Margin = new Thickness(213, 0, 10, 10);
      45:              Test.Children.Add(uc2);
      46:   
      47:              var data3 = new DataNotify();
      48:              data3.MaxData = 60;
      49:              data3.MinData = -10;
      50:              data3.MinRange = -10;
      51:              data3.MaxRange = 100;
      52:              data3.CurrentData = 36;
      53:              data3.Title = "土壤湿度";
      54:              data3.Unit = "%";
      55:              data3.ThemeSet = Theme.Mo;
      56:   
      57:              var uc3 = new TemperatureControl(data3);
      58:              uc3.Margin = new Thickness(633, 0, 10, 10);
      59:              Test.Children.Add(uc3);

    由于调用代码相当简单,我就不再这里赘述了,下面着重讲解其实现方式。

    首先在Silverlight项目中创建一个用户控件,我们命名为“TemperatureControl.xaml”,然后创建一个“ResData.xaml”资源文件项目,用于放置样式定义。

    然后开始对项目进行布局,组织xaml代码,得到的页面显示如下:

    image

    XAML文件代码如下:

       1:  <UserControl
       2:      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
       3:      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
       4:      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
       5:      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
       6:      mc:Ignorable="d"
       7:      x:Class="TinyFrame.Silverlight.TemperatureControl"
       8:      Loaded="UserControl_Loaded"
       9:      Width="200" Height="227">
      10:   
      11:      <Border Style="{StaticResource GridBorder}">
      12:          <Grid x:Name="LayoutRoot" Background="White">
      13:              <Grid.RowDefinitions>
      14:              <RowDefinition Height="30"/>
      15:              <RowDefinition/>
      16:              </Grid.RowDefinitions>
      17:              <Border Grid.Row="0" Style="{StaticResource TopBorder}">
      18:                  <TextBlock Style="{StaticResource TxtTitle}" Text="{Binding Title}" />
      19:              </Border>
      20:              <Border Grid.Row="1">
      21:                  <Grid>
      22:                      <Grid.ColumnDefinitions>
      23:                          <ColumnDefinition Width="40"/>
      24:                          <ColumnDefinition/>
      25:                          <ColumnDefinition/>
      26:                      </Grid.ColumnDefinitions>
      27:                      <Border Name="bRange" Style="{StaticResource RangeBorder}" BorderBrush="{Binding LineColor}"  VerticalAlignment="Bottom">
      28:                      <Grid>
      29:                          <Grid.RowDefinitions>
      30:                              <RowDefinition/>
      31:                              <RowDefinition/>
      32:                          </Grid.RowDefinitions>
      33:                              <TextBlock Grid.Row="0" Style="{StaticResource TxtCommon}" Name="txtMax" Foreground="{Binding lineColor}" VerticalAlignment="Top" ></TextBlock>
      34:                              <TextBlock Grid.Row="1" Style="{StaticResource TxtCommon}" Name="txtMin" Foreground="{Binding lineColor}" VerticalAlignment="Bottom"></TextBlock>
      35:                      </Grid>
      36:                      </Border>
      37:                      <Image Margin="-14,18,0,0" Source="{Binding BgImg}"  Grid.Column="1"/>
      38:                      <Border Grid.Column="2">
      39:                      <Grid>
      40:                      <TextBlock Margin="20,40,6,0" Text="{Binding CurrentData}" Foreground="{Binding IsOK}" Style="{StaticResource TxtValue}" ></TextBlock>
      41:                      <TextBlock Margin="20,65,6,0" Text="{Binding MaxData}"  Style="{StaticResource TxtValue}"></TextBlock>
      42:                      <TextBlock Margin="20,90,6,0" Text="{Binding MinData}"  Style="{StaticResource TxtValue}"></TextBlock>
      43:                      <TextBlock Style="{StaticResource TxtIntro}" Text="当前值:" Margin="-20,40,0,0" Name="i1"  />
      44:                      <TextBlock Style="{StaticResource TxtIntro}" Text="最大值:" Margin="-20,65,0,0"  Name="i2" />
      45:                      <TextBlock Style="{StaticResource TxtIntro}" Text="最小值:" Margin="-20,90,0,0"  Name="i3" />
      46:                          </Grid>
      47:                      </Border>
      48:                      <Border Style="{StaticResource BorderUnit}" Grid.Column="1" Margin="22,24,0,0">
      49:                      <TextBlock   Name="t" Text="{Binding Unit}"  />
      50:                      </Border>
      51:                      <Image x:Name="bStep" Style="{StaticResource ImgStep}" Source="{Binding BgStep}" Margin="11,0,0,27" Grid.Column="1" />
      52:                      <Canvas Height="120" Background="White" HorizontalAlignment="Left" Margin="24,47,0,0" Name="canvas1" VerticalAlignment="Top" Width="32" OpacityMask="Black" Grid.Column="1" />
      53:                  </Grid>
      54:              </Border>
      55:          </Grid>
      56:      </Border>
      57:  </UserControl>

    通过第一副图的对比,我们能轻易的知道上图中那些空白的位置放什么东西。

    由于在XAML中我采用了Binding来进行数据绑定,那么就展示下我用于数据绑定的类:

       1:   public class DataNotify : INotifyPropertyChanged
       2:      {
       3:          private double minData = 0;  //最小值
       4:          public double MinData
       5:          {
       6:              get
       7:              {
       8:                  return minData;
       9:              }
      10:              set
      11:              {
      12:                  if (value != minData)
      13:                  {
      14:                      minData = value;
      15:                      Notify("MinData");
      16:                  }
      17:              }
      18:          }
      19:   
      20:          private double maxData = 1;  //最大值
      21:          public double MaxData
      22:          {
      23:              get
      24:              {
      25:                  return maxData;
      26:              }
      27:              set
      28:              {
      29:                  if (value != maxData)
      30:                  {
      31:                      maxData = value;
      32:                      Notify("MaxData");
      33:                  }
      34:              }
      35:          }
      36:   
      37:          private double minRange = 0;  //刻度最小范围
      38:          public double MinRange
      39:          {
      40:              get { return minRange; }
      41:              set
      42:              {
      43:                  if (minRange != value)
      44:                  {
      45:                      minRange = value;
      46:                      Notify("MinRange");
      47:                  }
      48:              }
      49:          }
      50:   
      51:          private double maxRange = 90; //刻度最大范围
      52:          public double MaxRange
      53:          {
      54:              get { return maxRange; }
      55:              set
      56:              {
      57:                  if (maxRange != value)
      58:                  {
      59:                      maxRange = value;
      60:                      Notify("MaxRange");
      61:                  }
      62:              }
      63:          }
      64:   
      65:          private double currentData;  //当前值
      66:          public double CurrentData
      67:          {
      68:              get
      69:              {
      70:                  return currentData;
      71:              }
      72:              set
      73:              {
      74:                  if (value != currentData)
      75:                  {
      76:                      currentData = value;
      77:                      Notify("CurrentData");
      78:                  }
      79:              }
      80:          }
      81:   
      82:          private Brush isOK;   //指标是否正常
      83:          public Brush IsOK
      84:          {
      85:              get
      86:              {
      87:                  if (currentData >= minData && currentData <= maxData)
      88:                      return new SolidColorBrush(Colors.Black);
      89:                  else
      90:                      return new SolidColorBrush(Colors.Red);
      91:              }
      92:          }
      93:   
      94:          private string title;  //标题
      95:          public string Title
      96:          {
      97:              get
      98:              {
      99:                  return title;
     100:              }
     101:              set
     102:              {
     103:                  if (value != title)
     104:                  {
     105:                      title = value;
     106:                      Notify("Title");
     107:                  }
     108:              }
     109:          }
     110:   
     111:          private string unit;   //单位
     112:          public string Unit
     113:          {
     114:              get
     115:              {
     116:                  return unit;
     117:   
     118:              }
     119:              set
     120:              {
     121:                  if (value != unit)
     122:                  {
     123:                      unit = value;
     124:                      Notify("Unit");
     125:                  }
     126:              }
     127:          }
     128:   
     129:          private Theme themeSet;
     130:          public Theme ThemeSet
     131:          {
     132:              get
     133:              {
     134:                  return themeSet;
     135:              }
     136:              set
     137:              {
     138:                  if (value != themeSet)
     139:                  {
     140:                      themeSet = value;
     141:                      Notify("ThemeSet");
     142:                  }
     143:              }
     144:          }
     145:   
     146:          private string bgImg;  //背景默认值
     147:          public string BgImg
     148:          {
     149:              get
     150:              {
     151:                  return bgImg;
     152:              }
     153:              set
     154:              {
     155:                  if (value != bgImg)
     156:                  {
     157:                      bgImg = value;
     158:                      Notify("BgImg");
     159:                  }
     160:              }
     161:          }
     162:   
     163:          private string bgStep;  //水银柱块默认值
     164:          public string BgStep
     165:          {
     166:              get
     167:              {
     168:                  return bgStep;
     169:              }
     170:              set
     171:              {
     172:                  if (value != bgStep)
     173:                  {
     174:                      bgStep = value;
     175:                      Notify("BgStep");
     176:                  }
     177:              }
     178:          }
     179:   
     180:          private string lineColor;  //刻度范围条的颜色
     181:          public string LineColor
     182:          {
     183:              get
     184:              {
     185:                  return lineColor;
     186:              }
     187:              set
     188:              {
     189:                  if (lineColor != value)
     190:                  {
     191:                      lineColor = value;
     192:                      Notify("LineColor");
     193:                  }
     194:              }
     195:          }
     196:   
     197:          public event PropertyChangedEventHandler PropertyChanged;
     198:   
     199:          public void Notify(string propertyName)
     200:          {
     201:              if (PropertyChanged != null)
     202:                  PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
     203:          }
     204:      }

    上面的代码中,封装了温度计的所有需要的属性,包括刻度值,最大最小范围值,当前值,主题,标题,指标正常与否等。

    最后就是具体的事件组织方法:

       1:   public partial class TemperatureControl : UserControl
       2:      {
       3:          public TemperatureControl(DataNotify dataNotify)
       4:          {
       5:              InitializeComponent();
       6:              this.dataNotify = dataNotify;
       7:   
       8:              //绑定数据上下文
       9:              this.DataContext = dataNotify;
      10:   
      11:              //左侧刻度线的最大值最小值
      12:              double tempMinData = dataNotify.MinData;
      13:              if (timer == null)
      14:                  timer = new DispatcherTimer();
      15:              timer.Interval = new TimeSpan(100);
      16:              timer.Tick += (sender, e) =>
      17:              {
      18:                  tempMinData++;
      19:                  bRange.Dispatcher.BeginInvoke((Action)(() =>
      20:                  {
      21:                      bRange.Margin = GetThicknessByMaxMin();
      22:                      bRange.Height = (tempMinData - dataNotify.MinData) * THeight / (dataNotify.MaxRange - dataNotify.MinRange);
      23:                      txtMax.Text = tempMinData.ToString("0.0");
      24:                      txtMin.Text = dataNotify.MinData.ToString("0.0");
      25:                  }));
      26:                  if (tempMinData == dataNotify.MaxData)
      27:                      timer.Stop();
      28:              };
      29:              timer.Start();
      30:   
      31:              //当前值的显示
      32:              double tempMinRange = dataNotify.MinRange;
      33:              if (timerStep == null)
      34:                  timerStep = new DispatcherTimer();
      35:              timerStep.Interval = new TimeSpan(100);
      36:              timerStep.Tick += (sender, e) =>
      37:              {
      38:                  tempMinRange++;
      39:                  double value;
      40:                  if (dataNotify.MinRange < 0)
      41:                      value = (THeight / (dataNotify.MaxRange - dataNotify.MinRange)) * tempMinRange + (Math.Abs(dataNotify.MinRange)) * (120 / (dataNotify.MaxRange - dataNotify.MinRange));
      42:                  else
      43:                      value = (THeight / (dataNotify.MaxRange - dataNotify.MinRange)) * tempMinRange;
      44:                  if (value < 0)
      45:                      value = 0;
      46:                  bStep.Height = value;
      47:                  if (Math.Abs(tempMinRange - dataNotify.CurrentData) < 0.6)
      48:                  {
      49:                      timerStep.Stop();
      50:                  }
      51:              };
      52:              timerStep.Start();
      53:          }
      54:   
      55:          private readonly DispatcherTimer timer = null;
      56:          private readonly DispatcherTimer timerStep = null;
      57:          public DataNotify dataNotify;
      58:   
      59:          private const int THeight = 120;   //水银柱高度为120
      60:          private const int FHeight = 30;    //水银球高度为30
      61:   
      62:          //动态设置水银柱的Margin属性,以便于适应 带有正负值的场景
      63:          private Thickness GetThicknessByMaxMin()
      64:          {
      65:              double range = dataNotify.MaxRange - dataNotify.MinRange;
      66:              if (dataNotify.MinRange < 0)
      67:                  return new Thickness(0, 0, 0, FHeight + Math.Abs(dataNotify.MinRange)*THeight/range + (dataNotify.MinData) * THeight / range);
      68:              else
      69:                  return new Thickness(0, 0, 0, FHeight + (dataNotify.MinData) * THeight / range);
      70:          }
      71:   
      72:          private void UserControl_Loaded(object sender, RoutedEventArgs e)
      73:          {
      74:              //设置温度计的主题
      75:              switch (dataNotify.ThemeSet)
      76:              {
      77:                  case Theme.Red:
      78:                      dataNotify.BgImg = "Image/tem-red.png";
      79:                      dataNotify.BgStep = "Image/step-red.png";
      80:                      dataNotify.LineColor = "Red";
      81:                      break;
      82:                  case Theme.Blue:
      83:                      dataNotify.BgImg = "Image/tem-blue.png";
      84:                      dataNotify.BgStep = "Image/step-blue.png";
      85:                      dataNotify.LineColor = "Blue";
      86:                      break;
      87:   
      88:                  case Theme.Mo:
      89:                      dataNotify.BgImg = "Image/tem-mo.png";
      90:                      dataNotify.BgStep = "Image/step-mo.png";
      91:                      dataNotify.LineColor = "#00ACAE";
      92:                      break;
      93:   
      94:                  case Theme.Yellow:
      95:                      dataNotify.BgImg = "Image/tem-yellow.png";
      96:                      dataNotify.BgStep = "Image/step-yellow.png";
      97:                      dataNotify.LineColor = "#849C00";
      98:                      break;
      99:   
     100:                  case Theme.Orange:
     101:                      dataNotify.BgImg = "Image/tem-orange.png";
     102:                      dataNotify.BgStep = "Image/step-orange.png";
     103:                      dataNotify.LineColor = "#C88600";
     104:                      break;
     105:   
     106:                  case Theme.Green:
     107:                      dataNotify.BgImg = "Image/tem-green.png";
     108:                      dataNotify.BgStep = "Image/step-green.png";
     109:                      dataNotify.LineColor = "#178A00";
     110:                      break;
     111:   
     112:                  default:
     113:                      dataNotify.BgImg = "Image/tem-red.png";
     114:                      dataNotify.BgStep = "Image/step-red.png";
     115:                      dataNotify.LineColor = "Red";
     116:                      break;
     117:              }
     118:   
     119:              Draw(dataNotify.MinRange,dataNotify.MaxRange);
     120:          }
     121:   
     122:          //根据用户输入的最大刻度值,最小刻度值,来划刻度线
     123:          private void Draw(double minRange,double maxRange)
     124:          {
     125:              var step = (maxRange - minRange) / 120;
     126:              Line redLine = new Line();
     127:              redLine.X1 = 0;
     128:              redLine.Y1 = 0;
     129:              redLine.X2 = 0;
     130:              redLine.Y2 = 120;
     131:              redLine.StrokeThickness = 1;
     132:              redLine.Stroke = new SolidColorBrush(Colors.Black);
     133:              canvas1.Children.Add(redLine);
     134:              int j = 6;
     135:              for (int i = 0; i <= 6; i++)
     136:              {
     137:                  Line line = new Line();
     138:                  line.X1 = 0;
     139:                  line.Y1 = i * 20;
     140:   
     141:                  line.X2 =10;
     142:                  line.Y2 = i * 20;
     143:   
     144:                  TextBlock tb = new TextBlock();
     145:                  tb.Margin = new Thickness(12,i*20-8,0,0);
     146:                  tb.FontSize = 9;
     147:                  tb.Text = (((maxRange - minRange) / 6) * j + minRange).ToString("0");
     148:   
     149:                  line.StrokeThickness = 1;
     150:                  line.Stroke = new SolidColorBrush(Colors.Black);
     151:                  canvas1.Children.Add(line);
     152:                  canvas1.Children.Add(tb);
     153:                  for (int x = 0; x < 30; x++)
     154:                  {
     155:                      Line lineInner = new Line();
     156:                      lineInner.X1 = 0;
     157:                      lineInner.Y1 = (x + 1) * 4;
     158:   
     159:                      lineInner.X2 = 6;
     160:                      lineInner.Y2 = (x + 1) * 4;
     161:   
     162:                      lineInner.StrokeThickness = 1;
     163:                      lineInner.Stroke = new SolidColorBrush(Colors.Black);
     164:                      canvas1.Children.Add(lineInner);
     165:                  }
     166:   
     167:                  j--;
     168:              }
     169:          }
     170:   
     171:      }

    上面我加了一部分注释,解释的比较清楚了。由于写这个温度计的时候,我们时刻需要测量好屏幕上的水银柱高度和当前值的对应关系,所以里面有比较多的运算,具体的运算方式还希望能够自己推敲。代码我将在下一篇中附上。

  • 相关阅读:
    java架构师学习路线-http怎么做自动跳转https
    java架构师学习路线-如何在Azure创建容器Kubernetes集群
    java架构师学习路线-提取JDBC工具类 JDBCUtils
    java架构师学习路线-如何安装Kubernetes分布式容器
    java架构师学习路线-怎样使用kubernetes的网络隔离networkpolicy?
    java架构师学习路线-Java中增强一个类的几种方法
    java架构师学习路线-Spring事物控制特性有哪些?
    java架构师学习路线|一份完整的Java成神路线图
    java架构师学习路线-微服务系统架构
    最短路+线段树 空间宝石
  • 原文地址:https://www.cnblogs.com/scy251147/p/3737634.html
Copyright © 2011-2022 走看看