C# 从零开始使用Layui.Wpf库开发WPF客户端

news/2025/3/26 13:33:06/文章来源:https://www.cnblogs.com/magicMaQaQ/p/18788772

 一、简介

  最近需要开发一个桌面版的工具软件,之前用得更多的是Winform,作为一个全干工程师,我们也要兼顾下WPF,趁此机会再研究下开源控件库。

  MaQaQ:Winform真好用(有个HZHControls控件库,值得一看)。

二、准备工作

  找了下开源控件库,诸如MaterialDesignInXAML、HandyControl、AduSkin、Adonis-UI、Panuon.WPF.UI、DMSkin等等,以上这些我们都暂时不看。

  本次选用的控件库是Layui.WPF: GitHub - Layui-WPF-Team/Layui-WPF: 这是一个WPF版的Layui前端UI样式库。

  选用的原因是我的渣渣网络在打开其他库的时候都加载很慢,只有它脱颖而出,这就是缘分啊。

  MaQaQ:实际上MaterialDesignInXAML跟HandyControl我之前在别的项目有用过,这两个star数都挺高的,用起来也不错,HandyControl在Gitee上也有库,有兴趣的朋友可以去看看,这次我只是想试试新东西。  

  顺利访问到了GitHub库,我打开了里面的学习文档,他只给了我一个Hello world,真是干!得好。再往下翻,找到了使用说明:

   使用说明很简洁,看起来很轻松就能用上了,但我不信。那我们就去把源码下载下来吧,感恩开发者,他还给了示例(搬砖党狂喜啊)。打开程序源码,根据提示安装了.net5跟.net7后成功加载,找到LayuiApp,这是示例项目:

  运行后界面如下(PS:右上角的公告写得真好,值得一读!!!):

三、开发

  作为一个wpf菜鸡+资深搬砖党,此时不忙搬运,我们先打开LayuiApp的MainWindow.xaml,仔细研究一番:

  可以看到,原项目采用的是prism框架(一个用于构建复杂但组织良好的 WPF 应用程序的框架,实际上我并不认识它,这是通义千问告诉我的),总之,prism:ViewModelLocator.AutoWireViewModel="True"这一句,就是用于自动关联视图与视图模型。

  创建一个新的WPF程序,这里还是用我熟悉的.net6,慎重思考1秒后决定命名为ServerControlSystem,新建的项目里面自带有MainWindow.xaml。

  Nuget上引用LayUI.Wpf和Prism的相关库:

   为了实现prism的自动关联,我们要新建两个文件夹,Views和ViewModels,将MainWindow.xaml移动到Views文件夹下,在ViewModels文件夹中对应新建MainWindowViewModel.cs:

   当然,也可以自定义,这就需要我们自己去修改App.xaml.cs,添加配置:

protected override void ConfigureViewModelLocator()
{base.ConfigureViewModelLocator();ViewModelLocationProvider.Register<MainWindow, MainWindowViewModel>();
}

  这里我们还是用的自动关联,因为移动了MainWindow的位置,所以要对应修改下命名空间的路径(不想改你就直接删了重建吧):

  MainWindow.xaml:

<Window x:Class="ServerControlSystem.Views.MainWindow"...>
...
</Window>

  MainWindow.xaml.cs:

public partial class MainWindow : Window

  而在prism框架下,一般要将App的基类改为PrismApplication:

  App.xaml:

<prism:PrismApplication x:Class="ServerControlSystem.App"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="clr-namespace:ServerControlSystem"xmlns:prism="http://prismlibrary.com/"><Application.Resources><ResourceDictionary><ResourceDictionary.MergedDictionaries><ResourceDictionary Source="pack://application:,,,/LayUI.Wpf;component/Themes/Default.xaml" /></ResourceDictionary.MergedDictionaries></ResourceDictionary></Application.Resources>
</prism:PrismApplication>
View Code

  App.xaml.cs:

public partial class App : PrismApplication

  同时在prism框架下,一般是通过重写CreateShell方法来指定主窗口,且需要实现继承的RegisterTypes:

public partial class App : PrismApplication
{protected override Window CreateShell(){return Container.Resolve<MainWindow>();}protected override void OnStartup(StartupEventArgs e){base.OnStartup(e);DispatcherUnhandledException += App_DispatcherUnhandledException;}private void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e){LayMessage.Error(e.Exception.Message);//记录日志e.Handled = true;}protected override void RegisterTypes(IContainerRegistry containerRegistry){//注入自定义接口LayDialog.Register(Container.Resolve<IContainerExtension>());}
}
View Code

  现在,我们可以开始快乐搬运了,先小搬一下MainWindow.xaml,这里我们只是验证控件库的调用,所以就试一下Lay:LayTitleBar:

<Window x:Class="ServerControlSystem.Views.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:Lay="clr-namespace:LayUI.Wpf.Controls;assembly=LayUI.Wpf"xmlns:prism="http://prismlibrary.com/"Width="1080"Height="600"prism:ViewModelLocator.AutoWireViewModel="True"AllowsTransparency="True"WindowStartupLocation="CenterScreen"WindowStyle="None"Title="MainWindow" ><Grid><Lay:LayTitleBarBackground="{DynamicResource LighCyan}"CornerRadius="4"ResizeMode="CanResize"WindowState="{Binding WindowState, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">            </Lay:LayTitleBar></Grid>
</Window>
View Code

  然后再看模型,先实现基类ViewModelBase:

public abstract class ViewModelBase : BindableBase, INavigationAware, IRegionMemberLifetime, IConfirmNavigationRequest
{/// <summary>/// 导航器/// </summary>public IRegionManager Region;/// <summary>/// 弹窗服务/// </summary>public IDialogService Dialog;/// <summary>/// 事件聚合器/// </summary>public IEventAggregator Event;public ViewModelBase(){}public ViewModelBase(IContainerExtension container){this.Region = container.Resolve<IRegionManager>();this.Dialog = container.Resolve<IDialogService>();this.Event = container.Resolve<IEventAggregator>();}private DelegateCommand _LoadedCommand;public DelegateCommand LoadedCommand =>_LoadedCommand ?? (_LoadedCommand = new DelegateCommand(ExecuteLoadedCommand));/// <summary>///初始化界面加载/// </summary>public virtual void ExecuteLoadedCommand(){}/// <summary>/// 控制视图是否被缓存/// </summary>public bool KeepAlive => false;public virtual void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback){continuationCallback(true);}/// <summary>/// 控制实例是否被缓存/// </summary>/// <param name="navigationContext"></param>/// <returns></returns>public virtual bool IsNavigationTarget(NavigationContext navigationContext){return false;}/// <summary>/// 导航离开当前ViewModel时被调用/// </summary>/// <param name="navigationContext"></param>public virtual void OnNavigatedFrom(NavigationContext navigationContext){}/// <summary>/// 导航到当前ViewModel时被调用/// </summary>/// <param name="navigationContext"></param>public virtual void OnNavigatedTo(NavigationContext navigationContext){}
}
View Code

  再实现MainWindowViewModel:

public class MainWindowViewModel : ViewModelBase, IWindowAware
{private WindowState _WindowState;/// <summary>/// 窗体状态/// </summary>public WindowState WindowState{get { return _WindowState; }set { _WindowState = value; RaisePropertyChanged(); }}public MainWindowViewModel(IContainerExtension container) : base(container){}public override void ExecuteLoadedCommand(){base.ExecuteLoadedCommand();}public bool CanClosing(){var res = MessageBox.Show("确定关闭窗体吗?", "提示", MessageBoxButton.OKCancel);if (res == MessageBoxResult.OK) return true;else return false;}
}
View Code

  到这一步基本就完成了,编译生成一下,运行后就能得到一个简陋的空界面:

   之后,就可以根据需要,自己添加控件了。比如,你可以加上,标题栏就会美观一点:

<Lay:LayTitleBar.Header><Border Height="40"></Border>
</Lay:LayTitleBar.Header>

四、总结

  Winform真好写。

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

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

相关文章

聚点和闭包中点的等价条件

聚点有以下等价描述: 闭包中点有以下等价描述:这些等价描述在与导集和闭包的证明中能起到很大的作用。下面是一个例子。

Itext5生成高质量、易识别、适合小尺寸标签打印的二维码

高质量、易识别、小尺寸二维码生成 1.增大二维码的原始尺寸(例如 1000 x 1000 或更大),再缩放为 PDF 所需的大小。这样可以保留更多像素细节,提高识别率。 2.降低容错级别到 L 或 M,如果你的内容不是特别长或复杂的话,这样能减少密集度。 3.优化缩放方式: • 使用 Buffe…

【Docker】安装部署jenkins

docker安装部署jenkinsdocker安装jenkins  1、下载jenkins  2、创建挂载目录  3、启动jenkins容器  4、验证jenkins是否启动成功  5、获取管理员密码  6、下载安装插件 docker安装jenkins【1】下载jenkins拉取jenkins镜像 docker pull jenkins/jenkins:2.426.2-lts…

焊接保护气体智能调节控制器|节气装置

机器人焊接节气装置在焊接流程中扮演着至关重要的角色,它犹如一道坚实的屏障,为熔融金属营造一个纯净的焊接环境,有效抵御空气中氧气、氮气、水蒸气等不良因素的侵扰。具体而言,保护气体的多重功效可详尽阐述为以下几个层面:对焊缝的精心呵护。在诸如氩弧焊等精密焊接工艺…

线段树+扫描线,解决“静态矩阵加和+矩阵查询”问题

在试图用 CDQ 分治做这道题的时候遇到了一些麻烦,修改全部在查询之前的静态部分不会做,题解虽然还算详细,但是本人蒟蒻仍然无法理解,思考一上午,尝试过各种证明方法后,大致证明题解算法的正确性,记录在这里。先看题解的说法和代码:使用扫描线、线段树和差分离线解决静态…

centOS 上部署hadoop+mysql+hive 服务之mysql 和hive安装

hive默认存放元数据的数据库是Derby数据库,Derby数据库是嵌入式数据库,它只能单用户访问,也就是只能有一个会话连接到元数据存储,不适合多用户连接操作需求。比如,多用户同时进行查询或并发操作时,Derby无法处理,这会导致性能瓶颈或直接报错。因此,建议替换为用mysql在…

Pydantic根校验器:构建跨字段验证系统

title: Pydantic根校验器:构建跨字段验证系统 date: 2025/3/24 updated: 2025/3/24 author: cmdragon excerpt: Pydantic根校验器支持预处理(pre)与后处理(post)模式,可访问全量字段数据并修改值字典。多字段关联验证实现业务规则检查,如航班时间顺序与保险策略联动。分阶…

机器人焊接节气设备

WGFACS(Welding Gas Flow Automatic Control System)机器人焊接气体流量自适应控制系统。机器人焊接节气设备包含高速控制和采集系统与气体流量自适应装置。它专为在保证焊接质量的前提下,实现节能减排、降低用气成本而设计,广泛应用于汽车制造、航空航天、机械加工等多个行业…

做销售,会讲故事,能说服90%的客户!

在开始之前,先抛出一个问题:说服他人最有效的方式是什么? 或许很多人的第一反应是:事实和数据。毕竟,数据被认为是不会说谎的(当然,也存在数据造假的情况),人们似乎也更倾向于相信数据。正因如此,许多销售话术总会包含大量数据,诸如升学率达 xx%、录取率为 xx%、满意…

CSP安全策略与XSS漏洞的关系

CSP与XSS漏洞的关系1、CSP不依赖漏洞的存在: 2、CSP是独立的安全机制,其有效性取决于策略本身的严格性,而非漏洞是否存在。 例如: 严格CSP(基于nonce):即使站点存在XSS漏洞,攻击者也无法伪造合法的 nonce 值来执行脚本。 宽松CSP(允许unsafe-inline):若漏洞存在,攻…

vue项目启动报错---FATAL ERROR js堆内存不足

vue项目启动报错---FATAL ERROR js堆内存不足 估计项目太大 电脑性能扛不住 解决方法如下: 1.启动项目报错 估计是项目太大了 电脑性能不太行FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory 2.白话文---致命…