博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Silverlight自定义控件开发:温度计
阅读量:5323 次
发布时间:2019-06-14

本文共 17509 字,大约阅读时间需要 58 分钟。

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

调用代码如下:

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代码,得到的页面显示如下:

XAML文件代码如下:

1:  
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:      
12:          
13:              
14:              
15:              
16:              
17:              
18:                  
19:              
20:              
21:                  
22:                      
23:                          
24:                          
25:                          
26:                      
27:                      
28:                      
29:                          
30:                              
31:                              
32:                          
33:                              
34:                              
35:                      
36:                      
37:                      
38:                      
39:                      
40:                      
41:                      
42:                      
43:                      
44:                      
45:                      
46:                          
47:                      
48:                      
49:                      
50:                      
51:                      
52:                      
53:                  
54:              
55:          
56:      
57:  

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

由于在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:      }

 

 

 

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

转载于:https://www.cnblogs.com/scy251147/p/3737634.html

你可能感兴趣的文章
一些字符串的题
查看>>
第2章:标准输入与输出
查看>>
个人项目——买书
查看>>
POJ 2309 BST
查看>>
Codefroces 415B Mashmokh and Tokens
查看>>
HDU 3440 House Man
查看>>
Mysql 用户管理
查看>>
实验五
查看>>
焊接贴片
查看>>
C/C++掌握技能(一)
查看>>
数据库事务与锁详解
查看>>
实验3
查看>>
oracle导入大批量数据(20G)
查看>>
洛谷 P1508 Likecloud-吃、吃、吃
查看>>
Tile的更新
查看>>
在同一个页面设置两个选项卡菜单 滑动式导航
查看>>
Mybatis: 无效的列类型:1111错误
查看>>
DataGridView隔行显示不同的颜色
查看>>
封装数据库配置文件App配置文件
查看>>
python 执行shell命令
查看>>