C#开发上位机应用的一些选择

如果你不想看介绍,可以直接跳到优雅开发示例那里。

1. WASDK(WinUI 3)

Windows 应用 SDK 是一组新的开发人员组件和工具,它们代表着 Windows 应用开发平台的下一步发展。 Windows 应用 SDK 提供一组统一的 API 和工具,可供从 Windows 11 到 Windows 10 版本 1809 上的任何桌面应用以一致的方式使用。

Windows 应用 SDK 不会用 C++ 替换 Windows SDK 或现有桌面 Windows 应用类型,例如 .NET(包括 Windows 窗体和 WPF)和桌面 Win32。 相反,Windows 应用 SDK 使用一组通用 API 来补充这些现有工具和应用类型,开发人员可以在这些平台上依赖这些 API 来执行操作。 有关更多详细信息,请参阅Windows 应用 SDK 的优势。

这个WASDK目前是微软主推的开源的,UI部分是结合了WinUI 3。

2. WPF

欢迎使用 Windows Presentation Foundation (WPF) 桌面指南,这是一个与分辨率无关的 UI 框架,使用基于矢量的呈现引擎,构建用于利用现代图形硬件。 WPF 提供一套完善的应用程序开发功能,这些功能包括 Extensible Application Markup Language (XAML)、控件、数据绑定、布局、二维和三维图形、动画、样式、模板、文档、媒体、文本和版式。 WPF 属于 .NET,因此可以生成整合 .NET API 其他元素的应用程序。

目前WPF也已经开源,而且整体上更为成熟,Visual Studio就是WPF 4.x开发的,生态也比较好。

3. WinForms

欢迎使用 Windows 窗体的桌面指南,Windows 窗体是一个可创建适用于 Windows 的丰富桌面客户端应用的 UI 框架。 Windows 窗体开发平台支持广泛的应用开发功能,包括控件、图形、数据绑定和用户输入。 Windows 窗体采用 Visual Studio 中的拖放式可视化设计器,可轻松创建 Windows 窗体应用。

这个也是开源的,Winform算是上手即用的开发框架了,通过拖拉拽可以很轻松的创建出UI和编写对应的功能,对于UI美观程度不太重要的工业领域,这个用来做工具开发很简单,上手也容易。

4. UWP

UWP 是创建适用于 Windows 的客户端应用程序的众多方法之一。 UWP 应用使用 WinRT API 来提供强大的 UI 和高级异步功能,这些功能非常适用于 Internet 连接的设备。

微软对于UWP,只能说曾经爱过,当初UWP可是当红炸子鸡,号称跨windows全平台,不过现在也是跨windows全平台,可惜没搞好,不过虽然不够受重视,但是一时半会还是死不掉,毕竟WASDK还不够成熟。

为什么选择WASDK

通过上面的介绍,大家对于windows下的原生UI开发框架应该有了一些了解,如果抛开语言限制的话还有更多的选择,比如QT,各种前端的跨平台,像微软自己家的MAUI什么的,我之前还写了一篇WinUI迁移到即将"过时"的.NET MAUI个人体验

最近的微软Windows App SDK 1.1版本发布了,意味着BUG应该少了很多,也可以正式的在一些项目中使用了。通过官方的WinUI库,我们可以轻松的构建符合Win11设计规范的UI,由于UWP的种种问题,WPF和WinForms又是只开源,应该不会有大的新特性了,外加本人以前也经常玩玩UWP,通过前景和自己的喜好,肯定是选择WASDK了。

优雅开发示例

1. 做一个上位机应用



上图为应用的展示图,采用的WASDK1.1版本开发,目前已经上架了Windows商店,打包方式为MSIX,目前x64和arm64是分开的MSIX包,文档里提到可以多个MSIX包合成一个集合包,不过我采用上传多个包,让商店自动匹配。

此应用是为稚晖君的ElectronBot开发的第三方的上位机,名字就叫电子脑壳。下图是效果图展示,结合Surface平板,触摸体验良好,个人感觉很优雅。

B站演示视频

2. 整体的开发步骤

ElectronBot本身连接电脑采用的是libusb生成的驱动吧,这个不知道叙述的是否正确。

看下图大体能明白电脑和ElectronBot通过高速USB进行连接,当我们驱动安装成功就可以进行操作了。

电子脑壳应用=>ElectronBot.DotNet SDK=>LibUsbDotNet

底层调用采用的是LibUsbDotNet这个库进行底层数据传输的操作,我根据稚晖君提供的c++版本的sdk进行了封装。

目前c#版本的SDKElectronBot.DotNet是开源的,demo示例也是windowsAppSDK的,大家感兴趣的可以star一下。

开始创建项目前最好安装下Template Studio for WinUI

2.1 创建项目

选择模板进行创建,可以根据需要进行选择,本人选择如下。

由于ElectronBot .Net SDK本身已经开源,直接以上位机主体应用做讲解。下图为应用的依赖项,主要包含SDK和OpenCV相关的nuget包。

应用整体不复杂,通过.Net框架自带的DI容器进行对象生命周期的管理,通过MVVM进行数据的绑定和更新。

结合Win2D和OpenCV进行图形数据处理,然后通过SDK写入到usb设备里进行控制和展示。

2.2 关键点代码讲解

下面的代码是通过切换Combox事件,动态创建不同的表盘并绑定到MainWindows的控件上。

private ICommand _clockChangedCommand;
public ICommand ClockChangedCommand =>
_clockChangedCommand ?? (_clockChangedCommand = new RelayCommand(ClockChanged)); private async void ClockChanged()
{
var clockName = _clockComboxSelect.DataKey; if (!string.IsNullOrWhiteSpace(clockName))
{
var viewProvider = _viewProviderFactory.CreateClockViewProvider(clockName); Element = viewProvider.CreateClockView(clockName);
} await Task.CompletedTask;
} public UIElement Element
{
get => _element;
set => SetProperty(ref _element, value);
}

xaml代码如下。

通过此操作,能够正常显示表盘,数据刷新也能正常使用。

当切换到时钟模式的时候,另外一个定时器会定时抓取表盘并将xaml转化成图片进行传输,主要涉及到Win2D库的使用,代码如下。

if (_electron.Connect())
{
var bitmap = new RenderTargetBitmap();
await bitmap.RenderAsync(Element);
var pixels = await bitmap.GetPixelsAsync(); // Transfer the pixel data from XAML to Win2D for further processing.
using CanvasDevice canvasDevice = CanvasDevice.GetSharedDevice(); using CanvasBitmap canvasBitmap = CanvasBitmap.CreateFromBytes(
canvasDevice, pixels.ToArray(), bitmap.PixelWidth, bitmap.PixelHeight,
Windows.Graphics.DirectX.DirectXPixelFormat.B8G8R8A8UIntNormalized); using IRandomAccessStream stream = new InMemoryRandomAccessStream(); await canvasBitmap.SaveAsync(stream, CanvasBitmapFileFormat.Png); Bitmap image = new Bitmap(stream.AsStream()); var mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(image); var mat1 = mat.Resize(new OpenCvSharp.Size(240, 240), 0, 0, OpenCvSharp.InterpolationFlags.Area); var mat2 = mat1.CvtColor(OpenCvSharp.ColorConversionCodes.RGBA2BGR); var dataMeta = mat2.Data; var data = new byte[240 * 240 * 3]; Marshal.Copy(dataMeta, data, 0, 240 * 240 * 3); await Task.Run(() =>
{
if (_electron.Connect())
{
_electron.SetImageSrc(data); _electron.Sync();
}
}); }

上面代码通过RenderTargetBitmap和Win2D将Xaml元素转化成CanvasBitmap,然后再通过OpenCV将canvasBitmap转化成下位机可识别的字节数组,通过SDK进行传输到下位机。

整体的开发过程和UWP很相似,UI部分用到的很多API都是UWP的改名版本,上位机目前没有开源,所以只能截取部分代码进行讲解了,如果想交流大家可以评论区见。

3. 遇到的一些问题

目前Windows App SDK有一些BUG,在我使用的过程中主要发现使用WinRT的串口监听事件失效,已在github提了bug,回头应该能够修复,还有WinRT里的一些API只认UWP UI Api windows.UI开头的一些对象,还需要大家多使用多反馈,这样WASDK开发才能良性循环。

public async Task InitAsync()
{
// Target all Serial Devices present on the system
var deviceSelector = SerialDevice.GetDeviceSelector(); var myDevices = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(deviceSelector); deviceWatcher = DeviceInformation.CreateWatcher(deviceSelector); deviceWatcher.Added += new TypedEventHandler<DeviceWatcher, DeviceInformation>(this.OnDeviceAdded);
deviceWatcher.Removed += new TypedEventHandler<DeviceWatcher, DeviceInformationUpdate>(this.OnDeviceRemoved); }

上面代码注册的事件,在目前1.1版本的WASDK不生效,官方已经标注为BUG,当然在UWP里就正常,UWP在有些时候还是挺靠谱的嘛。

个人总结感悟

通过这个上位机应用的开发,也是对WASDK和UWP相关技术的使用能熟练一些了,从WPF到UWP再到WASDK和MAUI,XAML相关的开发都是可继承的,开发方式很相似,对于技术的迁移来说也算是没什么障碍吧,经常会听到很多人说微软出了这么多技术,都学不动了什么的,其实大家掌握内涵,对于新技术的接受还是很快的。

特别鸣谢以及参考推荐文档

感谢dino.c大佬的一个番茄钟,因为我的表盘其实就是抄他番茄钟的代码。

感谢h哥火火给的一些思路。

当然还要感谢超超,毕竟有些代码还是抄他的。

参考推荐文档如下

一个番茄钟

Win2D samples

opencvsharp

WindowsAppSDK

WindowsCommunityToolkit

ElectronBot

ElectronBot.DotNet

LibUsbDotNet

用WindowsAppSDK(WASDK)优雅的开发上位机应用的更多相关文章

  1. WinUI(WASDK)项目实践——优雅的开发上位机应用(新)

    摘要 这就是一个记录自己进行WinUI项目实践的博客,项目开源地址如下,觉得有帮助的可以去看看,因为项目都开源了,所以保姆级的讲解肯定不如直接看代码来的实在了. 电子脑壳项目地址 为什么叫新 因为之前 ...

  2. MFC开发上位机到底用Dialog结构还是文档结构?

    最近要跟着导师一起开发一款大型上位机.MFC新人在考虑用对话框结构还是文档结构. 虽然说书上说大型结构的软件都需要文档结构,但是目前来看,对话框可以实现功能,并且对话框的程序更小一些,节省资源加载速度 ...

  3. vc++MFC开发上位机程序

    用vc++MFC开发过不少跟单片机通讯的上位机程序了.搞懂了MFC架构,开发还是很快的,与底层单片机程序通讯,可以用串口.usb.网络.短信形式.串口现在用的越来越少了,一般电脑跟单片机在一块,使用串 ...

  4. VS2013开发上位机并调用MSCcommm控件的方式

    此文章适合VC++串口通信入门 一.页面布局及添加控件 1, 安装好vs2010如图 2, 新建一个基于VC++的MFC项目comm 注意:点击ok,然后next,这时候要将application t ...

  5. C#上位机开发(二)—— Hello,World

    上一篇大致了解了一下单片机实际项目开发中上位机开发部分的内容以及VS下载与安装,按照编程惯例,接下来就是“Hello,World!” 1.新建C#项目工程 首先选择新建Windows窗体应用(.NET ...

  6. 物联网框架ServerSuperIO.Core(.netcore)跨平台,一套设备驱动通吃嵌入式、上位机、云服务

    1.      概述... 2 2.      ServerSuperIO.Core跨平台开发环境... 2 3.      ServerSuperIO.Core特点... 2 4.      Ser ...

  7. [自娱自乐] 4、超声波测距模块DIY笔记(四)——终结篇·基于C#上位机软件开发

    前言 上一节我们已经基本上把超声波硬件的发射和接收模块全部做好了,接下来我们着手开发一个软硬结合的基于C#的平面定位软件! 目录 一.整体思路 二.效果提前展示 2-1.软件部分展示 2-2.硬件部分 ...

  8. 【专题教程第8期】基于emWin模拟器的USB BULK上位机开发,仅需C即可,简单易实现

    说明:1.如果你会emWin话的,就可以轻松制作上位机.做些通信和控制类上位机,比使用C#之类的方便程度一点不差,而且你仅会C语言就可以.2.并且成功将emWin人性化,可以做些Windows系统上的 ...

  9. 1-STM32物联网开发WIFI(ESP8266)+GPRS(Air202)系统方案安全篇(来看一下怎么样监听网络数据,监听电脑上位机软件的数据)

    首先安装网络监听软件 运行这个软件 这个软件安装到电脑上,默认是监听咱电脑上的网络通信 咱们先监听电脑的软件的网络通信数据,然后再说怎么监听Wi-Fi和APP的软件的网络通信数据 咱就监听咱基础篇的 ...

随机推荐

  1. OpenHarmony标准设备应用开发(三)——分布式数据管理

    (以下内容来自开发者分享,不代表 OpenHarmony 项目群工作委员会观点) 邢碌 上一章,我们通过分布式音乐播放器.分布式炸弹.分布式购物车,带大家讲解了 OpenAtom OpenHarmon ...

  2. 纯css 实现充电动画

    <template>   <div class="container">     <div class="header">& ...

  3. C#+Access 员工信息管理--简单的增删改查操作和.ini配置文件的读写操作。

    1.本程序的使用的语言是C#,数据库是Access2003.主要是对员工信息进行简单的增删改查操作和对.ini配置文件的读写操作. 2.代码运行效果如下: 功能比较简单.其中在得到查询结果后,在查询结 ...

  4. Python学习笔记: 用pprint更漂亮的打印数据

    pprint是一个标准库,它提供了pprint()函数 ,用来打印复杂数据时更漂亮 >>> from pprint import pprint >>> data = ...

  5. Django-ORM-连表正反操作

    一.A表男生,B表女生,C表关系 1通过A表查与某个男生有关系的所有女生 思想1:在A表中确认男生后,通过反查到C表,获取相关内容(QuerySet),然后再跨到B表获取所有女生信息. obj=mod ...

  6. 4.18-token验证

    在postman编写的每一个叫测试用例,既然收测试用例,那么就会有结果对比 API测试断言tests(判断一个接口测试用例是否成功,或者说是通过,是根据断言的三个条件都成立的情况下得到的结果) 协议状 ...

  7. Docker容器网络-基础篇

    开源Linux 一个执着于技术的公众号 Docker的技术依赖于Linux内核的虚拟化技术的发展,Docker使用到的网络技术有Network Namespace.Veth设备对.Iptables/N ...

  8. .NET混合开发解决方案6 检测是否已安装合适的WebView2运行时

    系列目录     [已更新最新开发文章,点击查看详细] 长青版WebView2运行时将作为Windows 11操作系统的一部分包含在内.但是在Windows 11之前(Win10.Win8.1.Win ...

  9. C#开发PACS医学影像三维重建(十三):基于人体CT值从皮肤渐变到骨骼的梯度透明思路

    当我们将CT切片重建为三维体之后,通常会消除一些不必要的外部组织来观察内部病灶, 一般思路是根据人体常见CT值范围来使得部分组织透明来达到效果, 但这是非黑即白的,即,要么显示皮肤,要么显示神经,要么 ...

  10. Spring 源码(9)Spring Bean的创建过程的前期准备

    回顾总结 到目前为止,Spring源码中AbstractApplicationContext#refresh方法的已经解读到第11个方法finishBeanFactoryInitialization, ...