需求

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

1.用户操作“开始”、“停止”之后,模拟“采集器”实时采集。

2.将实时“采集”的信息第一时间呈现到界面上。

首先上效果:

环境

Windows 10

Visual Studio 2019

.Net Framework 4.5.2

设计

UI设计:

功能设计:

室内详情信息的展开和收起;

点击“开始”,开启定时器开始采集;

点击“停止”,暂停定时器。

通过MVVM模式中的属性、命令绑定实现以上功能。

实现

1.自定义ViewModel模型基类(属性更改通知)

using System.ComponentModel;
using System.Runtime.CompilerServices;namespace Deamon.ViewModel
{/// <summary>/// ViewModel模型基类(属性更改通知)/// </summary>public class BaseViewModel : INotifyPropertyChanged{/// <summary>/// 当任何子属性更改其值时激发的事件/// </summary>public event PropertyChangedEventHandler PropertyChanged = (sender, e) => { };/// <summary>/// 调用此函数以触发 <see cref="PropertyChanged"/> 事件/// </summary>/// <param name="name"></param>public void RaisePropertyChanged(string name){PropertyChanged(this, new PropertyChangedEventArgs(name));}/// <summary>/// 更新属性,如果属性值没有发生变化,则不进行通知/// </summary>/// <typeparam name="T">属性类型</typeparam>/// <param name="properValue">返回的属性值</param>/// <param name="newValue">新的属性值</param>/// <param name="properName">属性名</param>protected void RaisePropertyChanged<T>(ref T properValue, T newValue, [CallerMemberName] string properName = ""){if (object.Equals(properValue, newValue))return;properValue = newValue;RaisePropertyChanged(properName);}}
}

2.自定义一个实现ICommand接口的基本命令执行操作

using System;
using System.Windows.Input;namespace Deamon.ViewModel
{/// <summary>/// 一个基本命令执行传递的操作/// </summary>public class RelayCommand : ICommand{#region 私有成员变量/// <summary>/// 要运行的操作/// </summary>private Action mAction;#endregion#region 公共事件/// <summary>/// 当 <see cref="CanExecute(object)"/> 的值发生变化时触发该事件/// </summary>public event EventHandler CanExecuteChanged = (sender, e) => { };#endregion#region 构造函数/// <summary>/// 默认构造函数/// </summary>/// <param name="action">命令要运行的操作</param>public RelayCommand(Action action){this.mAction = action;}#endregion #region 公共处理方法/// <summary>/// 判断传递过来的命令是否可以执行/// 目前该方法表示始终可以执行/// </summary>/// <param name="parameter">命令执行传递的参数</param>/// <returns></returns>public bool CanExecute(object parameter){return true;}/// <summary>/// 执行命令的操作/// </summary>/// <param name="parameter">命令执行传递的参数</param>public void Execute(object parameter){mAction();}#endregion}
}

3.根据房间信息定义一个继承自BaseViewModel的VM模型

using System;
using System.Timers;namespace Deamon.ViewModel
{/// <summary>/// 房间信息/// </summary>public class ChamberViewModel : BaseViewModel{#region 公共属性/// <summary>/// 温度/// </summary>private double temperature = 28.4;/// <summary>/// 温度/// </summary>public double Temperature{get { return temperature; }set{RaisePropertyChanged(ref temperature, value, nameof(Temperature));}}/// <summary>/// 湿度/// </summary>private double humidity = 64.5;/// <summary>/// 湿度/// </summary>public double Humidity{get { return humidity; }set{RaisePropertyChanged(ref humidity, value, nameof(Humidity));}}/// <summary>/// 电压/// </summary>private double voltage = 220.1;/// <summary>/// 电压/// </summary>public double Voltage{get { return voltage; }set{RaisePropertyChanged(ref voltage, value, nameof(Voltage));}}/// <summary>/// 电流/// </summary>private double current = 8;/// <summary>/// 电流/// </summary>public double Current{get { return current; }set{RaisePropertyChanged(ref current, value, nameof(Current));}}/// <summary>/// 电功率/// </summary>private double power = 164.5;/// <summary>/// 电功率/// </summary>public double Power{get { return power; }set{RaisePropertyChanged(ref power, value, nameof(Power));}}/// <summary>/// 电能/// </summary>private double energy = 1.3;/// <summary>/// 电能/// </summary>public double Energy{get { return energy; }set{RaisePropertyChanged(ref energy, value, nameof(Energy));}}#endregion#region 公共命令/// <summary>/// 开始命令/// </summary>public RelayCommand StartCommand{get{return new RelayCommand(() =>{timer.Interval = 100;timer.Start();});}}/// <summary>/// 停止命令/// </summary>public RelayCommand StopCommand{get{return new RelayCommand(() =>{timer.Stop();});}}#endregion#region 本地服务Timer timer;Random rand;public ChamberViewModel(){timer = new Timer(100);timer.Elapsed += Timer_Elapsed;rand = new Random();}private void Timer_Elapsed(object sender, ElapsedEventArgs e){Temperature = Math.Round(rand.NextDouble() * 10 + 20, 2);Humidity = Math.Round(rand.NextDouble() * 20 + 50, 2);Voltage = Math.Round(rand.NextDouble() * 5 + 219, 2);Current = Math.Round(rand.NextDouble() * 5 + 5, 2);Power = Math.Round(rand.NextDouble() * 100 + 135, 2);Energy = Energy + Math.Round(rand.NextDouble() * 0.1, 2);timer.Interval = 1000;}#endregion}
}

4.设计XAML实现UI,文本直接绑定VM模型中的属性和命令

<Page x:Class="Deamon.View.ChamberView"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:Deamon.View"Title="ChamberView"><Grid><Grid ><Viewbox><Image Source="..\Images\bg.jpg"/></Viewbox></Grid><Grid ><Expander Background="#DD000000" IsExpanded="True" ExpandDirection="Left" HorizontalAlignment="Right"><Expander.Header><StackPanel ><TextBlock Foreground="White" Text="室"/><TextBlock Foreground="White" Text="内"/><TextBlock Foreground="White" Text="详"/><TextBlock Foreground="White" Text="情"/></StackPanel></Expander.Header><Border Padding="10" HorizontalAlignment="Center" ><StackPanel><Rectangle Height="1" Fill="YellowGreen" Margin="0 5"/><WrapPanel><TextBlock Text="温度:" Foreground="AliceBlue"/><TextBlock Text="{Binding Temperature}" TextAlignment="Right" Padding="0 0 5 0" Width="60" Foreground="Lime"/><TextBlock Text="℃" Foreground="AliceBlue"/></WrapPanel><WrapPanel><TextBlock Text="湿度:" Foreground="AliceBlue"/><TextBlock Text="{Binding Humidity}" TextAlignment="Right" Padding="0 0 5 0" Width="60" Foreground="Lime"/><TextBlock Text="%" Foreground="AliceBlue"/></WrapPanel><Rectangle Height="1" Fill="YellowGreen" Margin="0 5"/><WrapPanel><TextBlock Text="电压:" Foreground="AliceBlue"/><TextBlock Text="{Binding Voltage}" TextAlignment="Right" Padding="0 0 5 0" Width="60" Foreground="Lime"/><TextBlock Text="V" Foreground="AliceBlue"/></WrapPanel><WrapPanel><TextBlock Text="电流:" Foreground="AliceBlue"/><TextBlock Text="{Binding Current}" TextAlignment="Right" Padding="0 0 5 0" Width="60" Foreground="Lime"/><TextBlock Text="A" Foreground="AliceBlue"/></WrapPanel><WrapPanel><TextBlock Text="功率:" Foreground="AliceBlue"/><TextBlock Text="{Binding Power}" TextAlignment="Right" Padding="0 0 5 0" Width="60" Foreground="Lime"/><TextBlock Text="W" Foreground="AliceBlue"/></WrapPanel><Rectangle Height="1" Fill="YellowGreen" Margin="0 5"/><WrapPanel><TextBlock Text="电能:" Foreground="AliceBlue"/><TextBlock Text="{Binding Energy}" TextAlignment="Right" Padding="0 0 5 0" Width="60" Foreground="Lime"/><TextBlock Text="kW·h" Foreground="AliceBlue"/></WrapPanel><Rectangle Height="1" Fill="YellowGreen" Margin="0 5"/><WrapPanel Margin="0 50 0 0" HorizontalAlignment="Center"><Button Command="{Binding StartCommand}" Content="开始" Width="50" Height="30"/><Button Command="{Binding StopCommand}" Content="停止" Width="50" Height="30"/></WrapPanel></StackPanel></Border></Expander></Grid></Grid>
</Page>

5.DataContext数据上下文赋值

using Deamon.ViewModel;
using System.Windows.Controls;namespace Deamon.View
{/// <summary>/// ChamberView.xaml 的交互逻辑/// </summary>public partial class ChamberView : Page{public ChamberView(){InitializeComponent();DataContext = new ChamberViewModel();}}
}

划重点

MVVM中分别是:Model、View、ViewModel,其中View是界面(UI),ViewModel是界面模型(Model For View),View和ViewModel之间的沟通一般通过两种方式:传递数据(属性)和传递操作(命令)。绑定的数据源一般情况下会设置到DataContext上面,如本文中:DataContext = new ChamberViewModel();

属性绑定(双向):

可以实现更改通知的属性是需要继承INotifyPropertyChanged接口的属性,同时需要在属性发生更改时(也就是在set中),手动的触发该事件PropertyChanged(this, new PropertyChangedEventArgs(name));.本文中自定义了一个RaisePropertyChanged方法,继承BaseViewModel基类的VIewModel可以直接调用RaisePropertyChanged实现属性通知。其中重载方法可以更方便的在属性的set中使用。

当ViewModel中的属性发送变化时,Binding会通知View刷新;同样,我们把绑定的Mode设置为TwoWay等方式时,当View中绑定的属性发生变化时,也会通知ViewModel中属性。

命令绑定(单向):

命令是单向传递的,即只能通过View传递给ViewModel一个动作(Action,后台执行的方法)。使用时,是将ViewModel继承ICommand接口类型(本文中的RelayCommand)定义的命令属性绑定到View中元素的Command属性值。但并不是所有的元素都具备Command属性,没有的我们需要通过使用System.Windows.Interactivity.dll进行扩展。

Over

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

WPF MVVM模式的应用——室内监控可视化相关推荐

  1. WPF自学入门(十一)WPF MVVM模式Command命令 WPF自学入门(十)WPF MVVM简单介绍...

    WPF自学入门(十一)WPF MVVM模式Command命令 在WPF自学入门(十)WPF MVVM简单介绍中的示例似乎运行起来没有什么问题,也可以进行更新.但是这并不是我们使用MVVM的正确方式.正 ...

  2. wpf mvvm模式下CommandParameter传递多参

    wpf mvvm模式下CommandParameter传递多参 原文:wpf mvvm模式下CommandParameter传递多参 CommandParameter一般只允许设置一次,所以如果要传递 ...

  3. C# WPF MVVM模式Prism框架下事件发布与订阅

    01 - 前言 处理同模块不同窗体之间的通信和不同模块之间不同窗体的通信,Prism提供了一种事件机制,可以在应用程序中低耦合的模块之间进行通信,该机制基于事件聚合器服务,允许发布者和订阅者之间通过事 ...

  4. C# WPF MVVM模式Prism框架从零搭建(经典)

    01 - 前言 目前最新的PRISM的版本是8.1.97,本节以6.3.0.0 讲解,可以在Github上获取PRISM的源码. Prism Github地址:https://github.com/P ...

  5. WPF MVVM模式 发送DataGird表格的数据到另一个页面显示

    WPF MVVM模式 发送DataGird表格的数据到另一个页面显示 这里我们是使用Messenger消息机制把这个页面的表格行数据发送到另一个页面显示,效果如下图: 首先在这个表格页面的ViewMo ...

  6. C# WPF MVVM模式Caliburn.Micro框架下事件发布与订阅

    01 - 前言 处理同模块不同窗体之间的通信和不同模块之间不同窗体的通信,Caliburn提供了一种事件机制,可以在应用程序中低耦合的模块之间进行通信,该机制基于事件聚合器服务,允许发布者和订阅者之间 ...

  7. 使用WPF+MVVM模式的小案例

    WPF+MVVM模式的小案例案例主要的目录结构 下面一步一步建立整个小程序的目录和相应的代码程序. 1.打开VS, 新建项目WPFDemo.Client.CustType(自己可以写自己的程序名称,这 ...

  8. C# WPF MVVM模式下在主窗体显示子窗体并获取结果

    01 - 前言 在winform中打开一个新的子窗体很简单,直接实例化窗体并show一下就可以: Form2 f2 = new Form2();f2.Show(); 或者 Form2 f2 = new ...

  9. WPF MVVM模式下的无阻塞刷新

    MVVM模式下的无阻塞刷新的两种方法: //传统模式下的无刷新调用(主线程开新线程,新线程又调用主线程来更新UI) //第1步先在线程内部计算出需要绑定的数据 //第2步然后再使用Invoke/Beg ...

最新文章

  1. 基于相交线的双目平面SLAM
  2. 使用JSP处理用户注册和登陆
  3. Fiddler的常用功能(Web断点调试)
  4. 区块链如何应用于保险行业
  5. python参数传递_python中的*和**参数传递机制
  6. php 页面加载进度条,HTML5/CSS3 网页加载进度条的实现,下载进度条等经典案例
  7. c语言木马源代码下载,木马编程 之超强服务... 附代码 原创.
  8. matlab空间球与空间圆求解,基于MATLAB的球管相贯空间曲线焊缝的数学模型
  9. Kotlin — 适用于服务器开发
  10. 基于SSM框架图书馆预约占座系统的设计与实现(附源码、论文)
  11. 2009国家公务员面试过关点点通
  12. 2D开源游戏引擎调研报告(一)
  13. iPhone5/iPad4越狱后10.3.3降级8.4.1详细教程
  14. 新浪微博视频下载教程
  15. 【更新】CVE-2020-0796:微软紧急发布SMBv3协议“蠕虫级”漏洞补丁通告
  16. mac下的c语言贪吃蛇
  17. error uploading crisocket: timed out waiting for the conditionswapoff -a # will turn off the swap
  18. 【分布式】一致性哈希和哈希槽
  19. 心法利器[55] | 算法工程师读论文思路
  20. 药检实验室如何规划设计

热门文章

  1. mysql中ddl语句有哪些_SQL中常用DDL语句
  2. 前端三大主流框架React、Vue.js、Angular的优缺点分析
  3. 阿里不遗余力阻击微信 胜算几何? 转载
  4. Windows客户端开发技能树
  5. 快速排序(详细图解 单路、双路、三路)
  6. 解决ubuntu无法安装搜狗输入法的问题
  7. java 修饰符默认_Java 默认修饰符 总结
  8. 天下苦“个人公众号认证”久矣,吾闻今可
  9. 基于android的中医养生app
  10. python中iloc用法_python pandas --loc、iloc用法