C# WPF设备监控软件(经典)-下篇

上节已经对本软件的功能和意图进行了详细讲解,这节就不再啰嗦,本节主要对功能实现和代码部分展开讲解.

01

前台代码

前台XAML:

<Window x:Class="EquipmentMonitor.EquipmentView"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:EquipmentMonitor"xmlns:cal="http://www.caliburnproject.org" mc:Ignorable="d" WindowStartupLocation="CenterScreen"Title="EquipmentMonitor" Height="610" Width="500" Icon="Display.png"><Window.Resources><Style TargetType="Label"><Setter Property="HorizontalAlignment" Value ="Center"/><Setter Property="VerticalAlignment" Value ="Center"/><Setter Property="FontSize" Value ="14"/><Setter Property="FontWeight" Value ="Black"/>
</Style><Style TargetType="ListBox"><Setter Property="HorizontalAlignment" Value ="Left"/><Setter Property="VerticalAlignment" Value ="Top"/><Setter Property="FontSize" Value ="14"/><Setter Property="FontWeight" Value ="Black"/><Setter Property="ItemTemplate"><Setter.Value><DataTemplate><Border BorderBrush="Gray" BorderThickness="2" Margin="2" ><StackPanel Orientation="Vertical" Background="{Binding BackBrush}"cal:Message.Attach="[Event MouseLeftButtonUp]=[BuildClick($source,$eventArgs)]"><Image Source="../Image/Display.png" Width="100" Height="100" /><Label Content="{Binding Title}" /></StackPanel></Border></DataTemplate></Setter.Value></Setter><Setter Property="ItemsPanel"><Setter.Value><ItemsPanelTemplate><WrapPanel  Orientation="Horizontal" /></ItemsPanelTemplate></Setter.Value></Setter>
</Style></Window.Resources><Grid><ListBox x:Name="EqplistBox"  ItemsSource="{Binding FileDTOList}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" Margin="2"/></Grid>
</Window>

前台代码异常简单,主要就是一个ListBox ,然后通过设置模板,将图片和标签进行界面显示

02


后台代码

① 数据模型:FileDTO.cs

using PropertyChanged;
using System;
using System.Collections.ObjectModel;
using System.Text;
using System.Windows.Media;namespace EquipmentMonitor.Model
{[AddINotifyPropertyChangedInterface]public class FileDTO{public FileDTO(){BackBrushList = new ObservableCollection<Brush>();BackBrushList.Add(Brushes.White);BackBrush = Brushes.White;CurrentTime = DateTime.Now;}public string Title { get; set; }public string MonitorPath { get; set; }public int TimeSpan { get; set; }public DateTime CurrentTime { get; set; }public Brush BackBrush { get; set; }public ObservableCollection<Brush> BackBrushList { get; set; }public override string ToString(){StringBuilder report = new StringBuilder();report.AppendLine($"[Title]  = [{Title}]");report.AppendLine($"[MonitorPath]  = [{MonitorPath}]");report.AppendLine($"[TimeSpan]  = [{TimeSpan}]");report.AppendLine($"[CurrentTime]  = [{CurrentTime}]");report.AppendLine($"[BackBrush]  = [{BackBrush}]");foreach (var item in BackBrushList){report.AppendLine($"[BackBrush]  = [{item}]");}return report.ToString();}}
}

这里重写了tostring方法,主要是为了方便log打印.

[AddINotifyPropertyChangedInterface]是PropertyChanged.dll下面的方法,在类顶部附加后,属性变更就可以自动通知界面,而不用一个一个去触发.

② 帮助类:

AutoStartHelper.cs

using Microsoft.Win32;
using System;
using System.Windows.Forms;namespace EquipmentMonitor.Helper
{public class AutoStartHelper{public static void AutoStart(bool isAuto = true, bool showinfo = true){try{if (isAuto == true){RegistryKey R_local = Registry.CurrentUser;//RegistryKey R_local = Registry.CurrentUser;RegistryKey R_run = R_local.CreateSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run");R_run.SetValue("应用名称", Application.ExecutablePath);R_run.Close();R_local.Close();}else{RegistryKey R_local = Registry.CurrentUser;//RegistryKey R_local = Registry.CurrentUser;RegistryKey R_run = R_local.CreateSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run");R_run.DeleteValue("应用名称", false);R_run.Close();R_local.Close();}}//if (showinfo)//      MessageBox.Show("您需要管理员权限修改", "提示");// Console.WriteLine("您需要管理员权限修改");catch (Exception ex){string content = DateTime.Now.ToLocalTime() + " 0001_" + "您需要管理员权限修改" + "\n" + ex.StackTrace + "\r\n";LogHelper.logWrite(content);}}}
}

没啥好讲的,就是为了软件第一次打开后,把启动信息添加到注册表,下次开机后软件可以自己启动;

LogHelper.cs:这是一个简易的log打印帮助类

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace EquipmentMonitor.Helper
{public class LogHelper{public static void logWrite(string Message, string StackTrace = null){if (!File.Exists(AppDomain.CurrentDomain.BaseDirectory + "\\log.txt")){File.Create(AppDomain.CurrentDomain.BaseDirectory + "\\log.txt").Close();}string fileName = AppDomain.CurrentDomain.BaseDirectory + "\\log.txt";string content = DateTime.Now.ToLocalTime() + Message + "\n" + StackTrace + "\r\n";StreamWriter sw = new StreamWriter(fileName, true);sw.Write(content);sw.Close(); sw.Dispose();}}
}

XMLHelper.cs:配置文件读取帮助类

using EquipmentMonitor.Model;
using System;
using System.Collections.ObjectModel;
using System.Xml;namespace EquipmentMonitor.Helper
{public class XMLHelper{public ObservableCollection<FileDTO> XmlDocReader(){try{//XmlDocument读取xml文件XmlDocument xmlDoc = new XmlDocument();xmlDoc.Load(AppDomain.CurrentDomain.BaseDirectory + "\\config.xml");//获取xml根节点XmlNode xmlRoot = xmlDoc.DocumentElement;if (xmlRoot == null){LogHelper.logWrite("xmlRoot is null");return null;}ObservableCollection<FileDTO> FileDTOList  = new ObservableCollection<FileDTO>();//读取所有的节点foreach (XmlNode node in xmlRoot.SelectNodes("FilePath")){FileDTOList.Add(new FileDTO{Title = node.SelectSingleNode("Title").InnerText,MonitorPath = node.SelectSingleNode("MonitorPath").InnerText,TimeSpan = int.Parse(node.SelectSingleNode("TimeSpan").InnerText)});}return FileDTOList;}catch (Exception ex){LogHelper.logWrite(ex.Message, ex.StackTrace);return null;}}}
}

③ Viewmodel部分:EquipmentViewModel.cs

using Caliburn.Micro;
using EquipmentMonitor.Helper;
using EquipmentMonitor.Model;
using PropertyChanged;
using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;namespace EquipmentMonitor
{[AddINotifyPropertyChangedInterface]public class EquipmentViewModel : Screen,IViewModel{public ObservableCollection<FileDTO> FileDTOList { get; set; } = new ObservableCollection<FileDTO>();private DispatcherTimer timer;public EquipmentViewModel(){Environment.CurrentDirectory = AppDomain.CurrentDomain.BaseDirectory;//自启动AutoStartHelper.AutoStart();//获取配置信息XMLHelper xmlHelper = new XMLHelper();FileDTOList = xmlHelper.XmlDocReader();FileSystemWatcher();//开启定时器timer = new DispatcherTimer();timer.Interval = TimeSpan.FromSeconds(10);timer.Tick += timer_Tick;timer.Start();Thread backThread = new Thread(StartRun);backThread.IsBackground = true;backThread.Start();}public void StartRun(){foreach (var fileDTO in FileDTOList){Task.Run(() =>{while (true){if (fileDTO.BackBrushList.Count > 1){Execute.OnUIThread(() =>{if (fileDTO.BackBrush == Brushes.Red){fileDTO.BackBrush = Brushes.Gray;}else{fileDTO.BackBrush = Brushes.Red;}});Thread.Sleep(1000);}Thread.Sleep(100);}});}}public void BuildClick(object sender, MouseButtonEventArgs e){StackPanel controls = sender as StackPanel;string title = null;foreach (var control in controls.Children){if(control is Label){title = (control as Label).Content.ToString();}}foreach (var fileDTO in FileDTOList){if (fileDTO.Title == title){fileDTO.CurrentTime = DateTime.Now;if (fileDTO.BackBrushList.Contains(Brushes.Red)){fileDTO.BackBrushList.Remove(Brushes.Red);fileDTO.BackBrush = Brushes.Gray;}return;}}}public void FileSystemWatcher(){try{foreach (var fileDTO in FileDTOList){FileSystemWatcher watcher = new FileSystemWatcher();try{LogHelper.logWrite($"the FileDTO is {fileDTO}");if (!string.IsNullOrEmpty(fileDTO?.MonitorPath)){watcher.Path = fileDTO?.MonitorPath;}else{LogHelper.logWrite("the MonitorPath is null");continue;}}catch (ArgumentException e){LogHelper.logWrite(e.Message);return;}//设置监视文件的哪些修改行为watcher.NotifyFilter = NotifyFilters.LastAccess| NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;watcher.Filter = "*.jpg";//添加事件句柄//当由FileSystemWatcher所指定的路径中的文件或目录的//大小、系统属性、最后写时间、最后访问时间或安全权限//发生更改时,更改事件就会发生watcher.Changed += new FileSystemEventHandler(OnChanged);watcher.Created += new FileSystemEventHandler(OnChanged);watcher.Deleted += new FileSystemEventHandler(OnChanged);watcher.EnableRaisingEvents = true;fileDTO.CurrentTime = DateTime.Now;}}catch (Exception ex){LogHelper.logWrite(ex.Message, ex.StackTrace);}}public void OnChanged(object source, FileSystemEventArgs e){Task.Run(() =>{foreach (var fileDTO in FileDTOList){//LogHelper.logWrite($"the FullPath = {e.FullPath},MonitorPath = {fileDTO.MonitorPath}");if (fileDTO.MonitorPath == Path.GetDirectoryName(e.FullPath)){fileDTO.CurrentTime = DateTime.Now;Execute.OnUIThread(() =>{if (fileDTO.BackBrushList.Contains(Brushes.Red)){fileDTO.BackBrushList.Remove(Brushes.Red);fileDTO.BackBrush = Brushes.Gray;}});//return;}}});}private void timer_Tick(object sender, EventArgs e){foreach (var fileDTO in FileDTOList){if(DiffSeconds(fileDTO.CurrentTime, DateTime.Now) >= fileDTO.TimeSpan){Execute.OnUIThread(() =>{if (!fileDTO.BackBrushList.Contains(Brushes.Red)){fileDTO.BackBrushList.Add(Brushes.Red);var equipmentWindow = (Window)this.GetView();if (equipmentWindow.WindowState == WindowState.Minimized){equipmentWindow.Show();equipmentWindow.WindowState = WindowState.Normal;equipmentWindow.Activate();}}LogHelper.logWrite($"The Alarm Equipment is {fileDTO.Title}");});}}}/// <summary>/// 相差秒/// </summary>/// <param name="startTime"></param>/// <param name="endTime"></param>/// <returns></returns>public double DiffSeconds(DateTime startTime, DateTime endTime){TimeSpan secondSpan = new TimeSpan(endTime.Ticks - startTime.Ticks);return secondSpan.TotalSeconds;}}
}

功能主体都是在这里实现的,

Thread backThread = new Thread(StartRun);backThread.IsBackground = true;

通过背景线程去更新界面alarm显示;

FileSystemWatcher watcher = new FileSystemWatcher();

通过FileSystemWatcher 去监测设备上文件夹是否有文件更新,

public void BuildClick(object sender, MouseButtonEventArgs e)

这个方法主要用来双击界面后消除设备的闪烁显示;

//开启定时器timer = new DispatcherTimer();timer.Interval = TimeSpan.FromSeconds(10);timer.Tick += timer_Tick;timer.Start();

开启定时器,用来检测是否超过设定时间,设备没有数据更新。以上就是此工具的所有功能了,如有疑问欢迎加我微信沟通.

源码下载:

链接:https://pan.baidu.com/s/1kA4scA_3t8F3eeLy-dRWAA 

提取码:6666

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/284109.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[转]互联网最大谣言:程序员35岁必淘汰?今天我就来击碎他

朋友&#xff0c;只要你是程序员&#xff0c;你一定知道996和“程序员35岁必死”的言论。 这两个话题在互联网上的讨论一次比一次激烈。 996工作制&#xff0c;众所周知&#xff0c;每天早上9点到岗&#xff0c;一直待到晚上9点&#xff0c;每周工作6天&#xff0c;很多互联网公…

【ArcGIS微课1000例】0057:将多波段栅格(影像.tif)背景设置为无数据nodata的方法

本文讲解将多波段栅格(影像.tif)背景设置为无数据nodata的方法。 文章目录 一、背景值识别二、背景值去除【推荐阅读】: 【ArcGIS微课1000例】0056:将单波段栅格背景设置为无数据NoData的方法 一、背景值识别 可以用【识别】工具来获取影像数据的背景值。 在背景上单击,…

华为HCIA认证H12-811题库新增

801、[单选题]178/832、在系统视图下键入什么命令可以切换到用户视图? A quit B souter C system-view D user-view 试题答案&#xff1a;A 试题解析&#xff1a;在系统视图下键入quit命令退出到用户视图。因此答案选A。 802、[单选题]“网络管理员在三层交换机上创建了V…

经典Java微服务架构教程 微服务从开发到部署

图书目录脑图&#xff1a; 本书根据开源项目整理&#xff0c;由于原在线文档无法正常使用&#xff0c;本人重新在Github上重新布署了一套在线文档。 书中讲解非常详细&#xff0c;并且有在线的视频教程&#xff0c;另有在线文档和在线的源码。 书中的代码由于PDF排版问题可能显…

linux下redis安装

转自&#xff1a;http://blog.java1234.com/blog/articles/311.html Redis从一开始就只支持Linux&#xff0c;后面虽然有团队搞出Window版本&#xff0c;但是我还是建议大伙安装到Linux中。 准备工作 &#xff08;wm VirtualBox&#xff09; VMware 以及Xshell https://redis…

cobbler koan自动重装系统

介绍 koan是kickstart-over-a-network的缩写&#xff0c;它是cobbler的客户端帮助程序&#xff0c;koan允许你通过网络提供虚拟机&#xff0c;也允许你重装已经存在的客户端。当运行时&#xff0c;koan会从远端的cobbler server获取安装信息&#xff0c;然后根据获取的安装信息…

Quartz.NET simple_demo

Quartz.NET是一个开源的作业调度框架&#xff0c;非常适合在平时的工作中&#xff0c;定时轮询数据库同步&#xff0c;定时邮件通知&#xff0c;定时处理数据等。 Quartz.NET允许开发人员根据时间间隔&#xff08;或天&#xff09;来调度作业。它实现了作业和触发器的多对多关系…

Hello Playwright:(9)执行 JavaScript 代码

Playwright 提供了大量的 API 用于与页面元素交互&#xff0c;但是在某些场景下还是不能完全满足要求。比如我们需要获得包括元素本身的 HTML&#xff0c;但是目前只有下列 API :InnerHTMLAsync 返回元素内的 HTML 内容InnerTextAsync 返回元素内的文本内容而使用 JavaScript 执…

【PhotoScan精品教程】photoscan无法启动此程序,因为计算机中丢失cholmod.dll解决办法

安装完航测软件photoscan&#xff0c;打开时提示&#xff1a;无法启动此程序&#xff0c;因为计算机中丢失 cholmod.dll解决办法。 错误提示&#xff1a; 解决办法&#xff1a; 并不是缺少该动态链接库文件&#xff0c;而是补丁文件拷贝错了。

什么是中台?企业为什么要建中台?从数据中台到AI中台。

从去年开始&#xff0c;好像就有一只无形的手一直将我与“微服务”、“平台化”、“中台化”撮合在一起&#xff0c;给我带来了很多的困扰和思考与收获。 故事的开始源于去年的技术雷达峰会&#xff0c;我在会上做了一场关于平台崛起的主题分享&#xff08;《The Rise of Plat…

老司机带你重构Android的v4包的部分源码

版权声明&#xff1a;本文为博主原创文章&#xff0c;未经博主允许不得转载。https://www.jianshu.com/p/a08d754944c4 转载请标明出处&#xff1a;https://www.jianshu.com/p/a08d754944c4 本文出自 AWeiLoveAndroid的博客 【前言】过年回家忙着干活&#xff0c;忙着给亲戚的孩…

.NET静态代码织入——肉夹馍(Rougamo) 发布1.1.0

肉夹馍是什么肉夹馍(https://github.com/inversionhourglass/Rougamo)通过静态代码织入方式实现AOP的组件。.NET常用的AOP有Castle DynamicProxy、AspectCore等&#xff0c;以上两种AOP组件都是通过运行时生成一个代理类执行AOP代码的&#xff0c;肉夹馍则是在代码编译时直接修…

Msys2 国内源(2017.3.30)

确定可用&#xff01; Server https://mirrors.tuna.tsinghua.edu.cn/msys2/msys/$arch转载于:https://www.cnblogs.com/baud/p/6644887.html

基于 IdentityServer3 实现 OAuth 2.0 授权服务【密码模式(Resource Owner Password Credentials)】...

密码模式&#xff08;Resource Owner Password Credentials Grant&#xff09;中&#xff0c;用户向客户端提供自己的用户名和密码。客户端使用这些信息&#xff0c;向"服务商提供商"索要授权。基于之前的 IdentityServer3 实现 OAuth 2.0 授权服务【客户端模式(Clie…

【GlobalMapper精品教程】035:用CASS自带数据创建高程地形、等高线教程

本文讲述globalmapper用CASS自带数据创建高程地形、等高线教程。 文章目录 1. 坐标生成点2. 点转高程格网3. 生成等高线4. 保存等高线CASS自带等高线数据dgx.dat预览:包含点号、编码、东坐标、北坐标、高程5列,可以不用做任何修改,在Globalmapper中生成点。 1. 坐标生成点 …

SaaS产品的免费试用到底该怎么做

”SaaS产品的免费试用&#xff0c;绝不仅仅只是开放产品试用期这么简单&#xff0c;很多企业并没有重视免费试用模式的搭建和转化路径“ 很多SaaS厂商的产品都会提供免费试用的机会&#xff0c;虽然试用的最终目标是促成用户为产品价值付费&#xff0c;但是很多SaaS厂商在开放系…

【.NET6+WPF】WPF使用prism框架+Unity IOC容器实现MVVM双向绑定和依赖注入

前言&#xff1a;在C/S架构上&#xff0c;WPF无疑已经是“桌面一霸”了。在.NET生态环境中&#xff0c;很多小伙伴还在使用Winform开发C/S架构的桌面应用。但是WPF也有很多年的历史了&#xff0c;并且基于MVVM的开发模式&#xff0c;受到了很多开发者的喜爱。并且随着工业化的进…

sql 中 limit 与 limit,offset连用的区别

① select * from table limit 2,1; #跳过2条取出1条数据&#xff0c;limit后面是从第2条开始读&#xff0c;读取1条信息&#xff0c;即读取第3条数据 ② select * from table limit 2 offset 1; #从第1条&#xff08;不包括&#xff09;数据开始取出2条…

【ArcGIS Pro微课1000例】0022:基于DEM进行流域分析生成流域图

文章目录 一、填洼二、流向分析三、计算流域一、填洼 填洼Fill,在进行水文分析后续操作前,首先要对DEM进行填洼,创建无凹陷点的DEM。 填洼需要使用水文分析工具下的【填洼】。 确定输入与输出即可。 填洼结果: 二、流向分析 在ArcGIS中使用的是八方向流量建模(D8算法),工…

Spring配置文件中bean标签的scope属性

转自&#xff1a;https://fj-sh-chz.iteye.com/blog/1775149 singleton &#xff08;默认属性&#xff09; Spring将Bean放入Spring IOC容器的缓存池中&#xff0c;并将Bean引用返回给调用者&#xff0c;spring IOC继续对这些Bean进行后续的生命管理。BeanFactory只管理一个共…