WPF+Prism+LiveCharts 搭建WPF开发框架
文章目录
前言
提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。
提示:以下是本篇文章正文内容
Prism
关于Prism的详细介绍如下
- 遵循设计模式,提升代码可维护性
MVVM 模式的有效应用:Prism 以 MVVM 模式为核心,将视图(View)和业务逻辑(ViewModel)分离。视图专注于界面展示,ViewModel 负责处理业务逻辑和数据交互。这种分离使得代码结构清晰,易于理解和维护。例如,当需要修改界面布局时,只需关注视图层的 XAML 代码,而不会影响到业务逻辑;反之,修改业务逻辑时也不会对视图造成影响。
依赖注入原则:Prism 支持依赖注入(Dependency Injection,DI),通过使用容器(如 Unity、Autofac 等)来管理对象的创建和生命周期。依赖注入使得组件之间的耦合度降低,提高了代码的可测试性和可维护性。例如,在 ViewModel 中需要使用某个服务时,只需通过构造函数注入该服务,而不需要在 ViewModel 内部直接创建服务实例,这样在测试时可以轻松替换服务的实现。 - 实现模块化开发,增强项目扩展性
模块的划分与管理:Prism 允许将应用程序划分为多个独立的模块,每个模块可以包含自己的视图、ViewModel、服务等。模块之间通过接口进行通信,降低了模块之间的耦合度。例如,一个大型的企业级应用可以划分为用户管理模块、订单管理模块、报表模块等,每个模块可以独立开发、测试和部署,当需要添加新功能时,只需开发新的模块并集成到应用程序中即可。
模块的动态加载:Prism 支持模块的动态加载,即可以在应用程序运行时根据需要加载或卸载模块。这对于一些需要根据用户权限或业务需求动态扩展功能的应用非常有用。例如,对于不同角色的用户,应用程序可以只加载该用户有权限使用的模块,提高了应用程序的灵活性和性能。 - 提供导航服务,优化用户体验
统一的导航机制:Prism 提供了强大的导航服务,使得在不同视图之间进行导航变得简单和统一。通过使用导航服务,开发者可以在 ViewModel 中轻松实现页面的跳转,而不需要在视图层编写复杂的导航逻辑。例如,在一个多页面的应用程序中,用户点击某个按钮后需要跳转到另一个页面,只需在对应的 ViewModel 中调用导航服务的方法即可实现。
导航参数的传递:Prism 的导航服务支持传递参数,使得在不同视图之间传递数据变得方便。例如,在一个商品列表页面点击某个商品后,需要跳转到商品详情页面并显示该商品的详细信息,这时可以通过导航参数将商品的 ID 传递到商品详情页面的 ViewModel 中,然后在 ViewModel 中根据商品 ID 从数据库或服务中获取商品的详细信息。 - 事件聚合器机制,促进组件间通信
松耦合的通信方式:Prism 的事件聚合器(Event Aggregator)提供了一种松耦合的组件间通信方式。不同的模块或组件可以通过事件聚合器发布和订阅事件,而不需要直接引用对方。例如,在一个购物车应用中,当商品添加到购物车时,购物车模块可以通过事件聚合器发布一个 “商品添加到购物车” 的事件,而订单统计模块可以订阅该事件,当事件发生时更新订单统计信息。
跨模块通信的支持:事件聚合器使得不同模块之间的通信变得简单和灵活。在大型应用程序中,不同模块可能位于不同的程序集或项目中,使用事件聚合器可以方便地实现跨模块的消息传递,提高了应用程序的整体协作性。 - 丰富的开发资源和社区支持
大量的示例和文档:Prism 拥有丰富的官方文档和示例代码,这些资源可以帮助开发者快速上手和掌握 Prism 的使用。无论是初学者还是有经验的开发者,都可以通过官方文档和示例代码了解 Prism 的各种功能和最佳实践。
活跃的社区:Prism 有一个活跃的开源社区,开发者可以在社区中交流经验、分享代码、解决问题。社区中还会不断涌现出各种扩展和插件,进一步丰富了 Prism 的功能和应用场景。
前置
1、先创建一个项目,然后新建好文件夹与安装好依赖
创建好后,添加引用。注意版本选择的是DryIoc。依赖注入的版本。
引入后还需要配置一下。原框架是Application。修改前后如下:
接着修改app.xaml.cs文件(这里继承PrismApplication可以是因为PrismApplication其实就是继承了Application)
修改完运行,可能会跳出来2个窗口,因为系统还有个默认的启动页面,禁止即可。这一行删掉就行。再运行就一个窗口了。
一、区域
1、创建Views 和 ViewModels文件夹。里面分别存放用户控件和模型。命名是prism框架要求,必须。
这里页面与模型绑定有2个办法。
-
一个是按照prism的命名规则,进行绑定。
即在页面上引入prism后设置 prism:ViewModelLocator.AutoWireViewModel=“True”。就会根据
UCA》UCAViewModel 自定绑定
这里需要将系统自带的MainWindow.xaml删除 ,在views文件夹下面新建一个同名的。这样命名空间就处在一个文件夹下
-
另一个方法是需要在App.xaml.cs里面手动绑定视图模型,这样可以不要用按照规则来命名。
如下:
2、绑定属性
在绑定的对应视图模型里面,继承BindableBase类后可以创建绑定属性(快捷创建 propfull tab tab)
RaisePropertyChanged() 方法要加上
MainWindowViewModel代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using WpfApp1.Views;
namespace WpfApp1.ViewModels
{
public class MainWindowViewModel:BindableBase
{
//定义代理命令(参数是string类型)
public DelegateCommand<string> ShowContentCmm { get; set; }
/// <summary>
/// 构造函数
/// </summary>
public MainWindowViewModel()
{
//实例化
ShowContentCmm = new DelegateCommand<string>(ShowContentCmmFun);
}
//绑定属性
/// <summary>
/// 显示内同
/// </summary>
private UserControl _ShowContent;
public UserControl ShowContent
{
get { return _ShowContent; }
set { _ShowContent = value;
//双向绑定,数据改变通知页面 MVVM
RaisePropertyChanged();
}
}
/// <summary>
/// 显示内容的命令
/// </summary>
/// <param name="pageName"></param>
public void ShowContentCmmFun(string pageName) {
if (pageName == "UCA") {
ShowContent = new UCA();
}
if (pageName == "UCB")
{
ShowContent = new UCB();
}
if (pageName == "UCC")
{
ShowContent = new UCC();
}
}
}
}
界面上
以上代码准备好,可以运行好后。开始使用区域
3、区域使用
将上面三个if判断的模块修改。进行解耦
将ABC三个用户控件注入到一个地方。其他视图模型想要哪个,就自己拿哪个就行了。
1、先将三个空间注入导航里面
2、方法内从区域管理里面通过导航取出
3、页面上要绑定区域名字与模型里面一致
运行后效果一致,但是实现了解耦的操作
二、模块化
就是为了引用别人的dll或者程序集
1、根据区域的代码 创建新的WPF程序 模块A 模块B.并修改输出属性
新建后 将输出类型改为类库,然后将自带的文件全部删除。(我这里名字打错了 应该是ModuleA和ModuleB 而不是model)
为什么不直接创建类库,是因为要在模块里面新增窗口,用户控件等。直接创建类库不支持。不知道以后可不可以
文件目录依旧创建Views和 ViewModels。与之前一致,并且安装prism.DryIoc的包
- 要再2个类库下面各自新建一个生成文件。ModuleAProfile 和ModuleBProfile。名称无所谓
在类里面继承prism的模块接口IModule并且要实现接口
2、如何引用。直接项目的引用就不演示了,直接演示引用dll
1、重新生成moduleA和B 后 打开文件夹位置 找到dll文件
2、在主项目里面创建modules文件夹,将2个dll放进去。并且都是始终复制
3、重写IModuleCatalog方法
运行后即可
3、调试
调试的时候 还是要直接引入项目比较好调试
引入项目是
1、添加项目引用
2、重写ConfigureModuleCatalog方法
在里面新增模块的加载文件即可。运行起来就可以打断点调试
三、导航
1、在调用页面的时候,可以传入参数
界面传入的参数也需要添加
2、在被调用的模块里面,需要继承INavigationAware接口,并实现三个接口。来接收参数
模块A页面的内容也是绑定到了Msg
记得重新加载一下模块A,并将dll文件重新复制到主程序的modules文件夹下运行。后就可以看到
3、确认导航
实现离开页面的时候,弹窗。效果如下
1、将继承的INavigationAware改为继承IConfirmNavigationRequest。其中IConfirmNavigationRequest也是继承了INavigationAware
所以之前实现的三个接口不会报错。并且还会多一个接口需要继承就是离开后的弹窗提示接口
重新生成后 替换modules文件夹里面的dll 。运行即可实现
4、实现导航上的后退 前进功能。
1、定义一个后退的委托命令 BackCmm并实例化BackCmmFunc
2.定义一个导航记录IRegionNavigationJournal。并在切换导航的时候 记录到这里面(通过一个回调方法即可)
3、实现 BackCmmFunc方法的前进 后退 并将方法绑定到后退按钮上
代码如下:
运行后 跳转几个页面即可实现后退功能了
四、对话服务
就是实现对话框。使用prism的对话服务实现对话框。
使用prism的对话服务可以更简单使用传参数以及返回处理结果
比WPF自带的对话框更好使用
1、创建对话框
我选择在ModuleB里面继续创建对话框
1、新增一个DiaLog用户空间 并且绑定DiaLogViewModel
2、新增界面的布局以及取消确认按钮绑定等事件
3、ViewModel编写事件
- ViewModel代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ModelB.ViewModels
{
public class DiaLogViewModel : BindableBase, IDialogAware
{
//public DialogCloseListener RequestClose => throw new NotImplementedException();
private DialogCloseListener _requestClose;
public DialogCloseListener RequestClose
{
get => _requestClose;
set => SetProperty(ref _requestClose, value);
}
/// <summary>
/// 标题
/// </summary>
public string Title { get; set; }
private string _context;
public string Context
{
get { return _context; }
set { _context = value; }
}
//确定
public DelegateCommand ConfirmCmm { get; set; }
//取消
public DelegateCommand ConcelCmm { get; set; }
public DiaLogViewModel() {
//实例化
ConfirmCmm = new DelegateCommand(ConfirmFunc);
ConcelCmm = new DelegateCommand(ConcelFunc);
}
/// <summary>
/// 确定
/// </summary>
public void ConfirmFunc()
{
DialogParameters parames = new DialogParameters();
parames.Add("result", "这很成功");
var result = new DialogResult
{
Parameters = parames,
Result = ButtonResult.OK
};
RequestClose.Invoke(result);
}
/// <summary>
/// 取消
/// </summary>
public void ConcelFunc()
{
DialogParameters parames = new DialogParameters();
parames.Add("result", "已取消");
var result = new DialogResult
{
Parameters = parames,
Result = ButtonResult.No
};
RequestClose.Invoke(result);
}
/// <summary>
/// 是否可以关闭对话框
/// </summary>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public bool CanCloseDialog()
{
return true;
}
/// <summary>
/// 关闭周期事件
/// </summary>
/// <exception cref="NotImplementedException"></exception>
public void OnDialogClosed()
{
}
/// <summary>
/// 打开对话框事件
/// </summary>
/// <param name="parameters"></param>
/// <exception cref="NotImplementedException"></exception>
public void OnDialogOpened(IDialogParameters parameters)
{
if (parameters.ContainsKey("bt") && parameters.ContainsKey("xx"))
{
Title = parameters.GetValue<string>("bt");
Context = parameters.GetValue<string>("xx");
}
}
}
}
- view代码如下
<UserControl x:Class="ModelB.Views.DiaLog"
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:ModelB.Views"
mc:Ignorable="d"
d:DesignHeight="200" d:DesignWidth="400">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Text="温馨提示" Background="#F0F3F6" Padding="3,5,0,0" Height="40" FontSize="20" VerticalAlignment="Center"></TextBlock>
<TextBlock Grid.Row="1" Text="{Binding Context}" FontSize="50" ></TextBlock>
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right">
<Button Content="确定" Margin="0,0,10,0" Width="50" Height="30" FontSize="17" Command="{Binding ConfirmCmm}"></Button>
<Button Content="取消" FontSize="17" Width="50" Height="30" Margin="0,0,0,0" Command="{Binding ConcelCmm}"></Button>
</StackPanel>
</Grid>
</UserControl>
生成文件内加载为弹窗 containerRegistry.RegisterDialog<DiaLog, DiaLogViewModel>();
2、打开对话框
1、创建一个打开对话框按钮,并绑定方法和传入参数,调用对应的对话框
2、创建prism的对话框服务IDialogService。注入进来
3、实现打开对话框按钮的方法。并传入对应的参数
代码如下:
using Prism.Navigation.Regions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using WpfApp1.Views;
namespace WpfApp1.ViewModels
{
public class MainWindowViewModel:BindableBase
{
/// <summary>
/// 对话框
/// </summary>
public DelegateCommand<string> ShowDalog { get; set; }
/// <summary>
/// 导航记录
/// </summary>
private IRegionNavigationJournal regionNavigationJournal;
//定义代理命令(参数是string类型)
public DelegateCommand<string> ShowContentCmm { get; set; }
/// <summary>
/// 定义委托后退命令
/// </summary>
public DelegateCommand BackCmm { get; set; }
/// <summary>
/// 区域管理
/// </summary>
private readonly IRegionManager regionManager;
/// <summary>
/// 对话框服务
/// </summary>
private readonly IDialogService dialogService;
/// <summary>
/// 构造函数
/// </summary>
public MainWindowViewModel(IRegionManager _regionManager, IDialogService _dialogService)
{
//实例化
ShowContentCmm = new DelegateCommand<string>(ShowContentCmmFun);
BackCmm = new DelegateCommand(BackCmmFunc);
ShowDalog = new DelegateCommand<string>(ShowDiaLogFunc);
regionManager = _regionManager;
dialogService = _dialogService;
}
//绑定属性
/// <summary>
/// 显示内同
/// </summary>
private UserControl _ShowContent;
public UserControl ShowContent
{
get { return _ShowContent; }
set { _ShowContent = value;
//双向绑定,数据改变通知页面 MVVM
RaisePropertyChanged();
}
}
/// <summary>
/// 打开对话框
/// </summary>
/// <param name="diaLogName"></param>
private void ShowDiaLogFunc(string diaLogName)
{
DialogParameters parames = new DialogParameters();
parames.Add("bt", "动态标题哦");
parames.Add("xx", "大家好啊,我是弹窗测试哦");
dialogService.ShowDialog(diaLogName, parames, result => {
var aab = result;
if (result.Result == ButtonResult.OK)
{
var aa = result.Parameters.GetValue<string>("result");
}
});
}
/// <summary>
/// 后退命令
/// </summary>
public void BackCmmFunc() {
if (regionNavigationJournal != null && regionNavigationJournal.CanGoBack) regionNavigationJournal.GoBack();
//regionNavigationJournal.CanGoForward 前进
}
/// <summary>
/// 显示内容的命令
/// </summary>
/// <param name="pageName"></param>
public void ShowContentCmmFun(string pageName) {
NavigationParameters keyValuePairs = new NavigationParameters();
//可以添加多个参数
keyValuePairs.Add("msgA", "你好,我是界面A");
keyValuePairs.Add("msgB", "你好,我是界面B");
//区域管理内,通过区域名字,请求导航
//传入参数
//在回调方法里面记录导航
regionManager.Regions["ContenRegion"].RequestNavigate(pageName, callback=> {
regionNavigationJournal = callback.Context.NavigationService.Journal;
}, keyValuePairs);
//if (pageName == "UCA") {
// ShowContent = new UCA();
//}
//if (pageName == "UCB")
//{
// ShowContent = new UCB();
//}
//if (pageName == "UCC")
//{
// ShowContent = new UCC();
//}
}
}
}
五、发布订阅
1、定义发布消息的事件MsgEvent
不需要实现任何方法
2、新建发布按钮,并绑定对应的方法
3、新建订阅按钮,并绑定对应的方法
4、新建取消订阅按钮,并绑定对应的方法
5、引入prism的订阅服务
代码如下:
using Prism.Navigation.Regions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interop;
using WpfApp1.Event;
using WpfApp1.Views;
namespace WpfApp1.ViewModels
{
public class MainWindowViewModel:BindableBase
{
/// <summary>
/// 对话框
/// </summary>
public DelegateCommand<string> ShowDalog { get; set; }
/// <summary>
/// 导航记录
/// </summary>
private IRegionNavigationJournal regionNavigationJournal;
//定义代理命令(参数是string类型)
public DelegateCommand<string> ShowContentCmm { get; set; }
/// <summary>
/// 定义委托后退命令
/// </summary>
public DelegateCommand BackCmm { get; set; }
/// <summary>
/// 消息发布
/// </summary>
public DelegateCommand MsgPush { get; set; }
/// <summary>
/// 订阅
/// </summary>
public DelegateCommand Pub { get; set; }
/// <summary>
/// 取消订阅
/// </summary>
public DelegateCommand NoPub { get; set; }
/// <summary>
/// 区域管理
/// </summary>
private readonly IRegionManager regionManager;
/// <summary>
/// 对话框服务
/// </summary>
private readonly IDialogService dialogService;
/// <summary>
/// 发布订阅服务
/// </summary>
private readonly IEventAggregator _eventAggregator;
/// <summary>
/// 构造函数
/// </summary>
public MainWindowViewModel(IRegionManager _regionManager, IDialogService _dialogService, IEventAggregator eventAggregator)
{
//实例化
ShowContentCmm = new DelegateCommand<string>(ShowContentCmmFun);
BackCmm = new DelegateCommand(BackCmmFunc);
ShowDalog = new DelegateCommand<string>(ShowDiaLogFunc);
MsgPush = new DelegateCommand(MsgPushCmm);
Pub = new DelegateCommand(PubCmm);
NoPub = new DelegateCommand(NoPubComm);
regionManager = _regionManager;
dialogService = _dialogService;
_eventAggregator = eventAggregator;
}
/// <summary>
/// 取消订阅
/// </summary>
public void NoPubComm()
{
_eventAggregator.GetEvent<MsgEvent>().Unsubscribe(pub);
}
/// <summary>
/// 订阅
/// </summary>
public void PubCmm()
{
_eventAggregator.GetEvent<MsgEvent>().Subscribe(pub);
}
/// <summary>
/// 订阅消息处理(委托)
/// </summary>
/// <param name="obj"></param>
/// <exception cref="NotImplementedException"></exception>
private void pub(string obj)
{
MessageBox.Show($"收到的关怀{obj}");
}
/// <summary>
/// 发布
/// </summary>
public void MsgPushCmm()
{
_eventAggregator.GetEvent<MsgEvent>().Publish("温馨提示:最近降温,请注意保暖哦");
}
//绑定属性
/// <summary>
/// 显示内同
/// </summary>
private UserControl _ShowContent;
public UserControl ShowContent
{
get { return _ShowContent; }
set { _ShowContent = value;
//双向绑定,数据改变通知页面 MVVM
RaisePropertyChanged();
}
}
/// <summary>
/// 打开对话框
/// </summary>
/// <param name="diaLogName"></param>
private void ShowDiaLogFunc(string diaLogName)
{
DialogParameters parames = new DialogParameters();
parames.Add("bt", "动态标题哦");
parames.Add("xx", "大家好啊,我是弹窗测试哦");
dialogService.ShowDialog(diaLogName, parames, result => {
var aab = result;
if (result.Result == ButtonResult.OK)
{
var aa = result.Parameters.GetValue<string>("result");
}
});
}
/// <summary>
/// 后退命令
/// </summary>
public void BackCmmFunc() {
if (regionNavigationJournal != null && regionNavigationJournal.CanGoBack) regionNavigationJournal.GoBack();
//regionNavigationJournal.CanGoForward 前进
}
/// <summary>
/// 显示内容的命令
/// </summary>
/// <param name="pageName"></param>
public void ShowContentCmmFun(string pageName) {
NavigationParameters keyValuePairs = new NavigationParameters();
//可以添加多个参数
keyValuePairs.Add("msgA", "你好,我是界面A");
keyValuePairs.Add("msgB", "你好,我是界面B");
//区域管理内,通过区域名字,请求导航
//传入参数
//在回调方法里面记录导航
regionManager.Regions["ContenRegion"].RequestNavigate(pageName, callback=> {
regionNavigationJournal = callback.Context.NavigationService.Journal;
}, keyValuePairs);
//if (pageName == "UCA") {
// ShowContent = new UCA();
//}
//if (pageName == "UCB")
//{
// ShowContent = new UCB();
//}
//if (pageName == "UCC")
//{
// ShowContent = new UCC();
//}
}
}
}
截图解析:
六、调用API接口
1、封装请求接口类
代码:
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RestSharp;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using WpfDemo.DTOs;
using WpfDemo.Helpers;
using static WpfDemo.HeepClients.APIResponse;
namespace WpfDemo.HeepClients
{
/// <summary>
/// 调用API工具类
/// </summary>
public class HttpRestClient
{
private readonly RestClient _client;
private readonly string _url = "http://localhost:61176/api/"; //可以从配置文件拿取
private readonly ConfigHelper _configHelper;
public HttpRestClient(RestClient restClient, ConfigHelper configHelper)
{
_client = new RestClient(_url);
_configHelper = configHelper;
}
/// <summary>
/// 一般接口请求
/// </summary>
/// <param name="requestParames"></param>
/// <returns></returns>
public ApiResult<T> Execute<T>(APIRequest requestParames)
{
var token = _configHelper.GetConfig("token");
//创建RestRequest请求时,添加具体路径
RestRequest request = new RestRequest(requestParames.Route, requestParames.Method);
request.AddHeader("Context-Type", requestParames.ContentType);
request.AddHeader("Authorization", token);
if (requestParames.Parames != null)
{
// 将参数序列化为JSON格式并添加到请求体中(假设发送数据类型为JSON)
string jsonData = JsonConvert.SerializeObject(requestParames.Parames);
request.AddParameter("application/json", jsonData, ParameterType.RequestBody);
}
var response = _client.Execute(request);
if (response.Content != null)
{
try
{
return JsonConvert.DeserializeObject<ApiResult<T>>(response.Content);
}
catch (JsonException)
{
// 如果反序列化失败,根据需求可以设置默认值或进行其他处理
return new ApiResult<T>
{
Code = "99",
Message = "序列化错误"
};
}
}
return new ApiResult<T>
{
Code = "00",
Message = "接口请求失败"
};
}
/// <summary>
/// 分页接口请求
/// </summary>
/// <param name="requestParames"></param>
/// <returns></returns>
public PageApiResult<T> PageExecute<T>(APIRequest requestParames)
{
var token = _configHelper.GetConfig("token");
//这里拿取的token是在登录接口放进去的
// _configHelper.SetConfig("token", $"Bearer {result.Data.Token.ToString()}");
//创建RestRequest请求时,添加具体路径
RestRequest request = new RestRequest(requestParames.Route, requestParames.Method);
request.AddHeader("Context-Type", requestParames.ContentType);
request.AddHeader("Authorization", token);
if (requestParames.Parames != null)
{
// 将参数序列化为JSON格式并添加到请求体中(假设发送数据类型为JSON)
string jsonData = JsonConvert.SerializeObject(requestParames.Parames);
request.AddParameter("application/json", jsonData, ParameterType.RequestBody);
}
var response = _client.Execute(request);
if (response.Content != null)
{
try
{
return JsonConvert.DeserializeObject<PageApiResult<T>>(response.Content);
}
catch (JsonException)
{
// 如果反序列化失败,根据需求可以设置默认值或进行其他处理
return new PageApiResult<T>
{
Code = "99",
Message = "序列化错误"
};
}
}
return new PageApiResult<T>
{
Code = "00",
Message = "接口请求失败"
};
}
}
}
使用的相关的类型
/// <summary>
/// 一般返回结果
/// </summary>
/// <typeparam name="T"></typeparam>
public class ApiResult<T>
{
/// <summary>
/// 返回码
/// </summary>
public string Code { get; set; }
/// <summary>
/// 提示信息
/// </summary>
public string Message { get; set; }
/// <summary>
/// 成功或者失败
/// </summary>
public bool Success { get; set; }
/// <summary>
/// 返回结果
/// </summary>
public T Data { get; set; }
}
/// <summary>
/// 分页返回接口
/// </summary>
/// <typeparam name="T"></typeparam>
public class PageApiResult<T> {
/// <summary>
/// 返回码
/// </summary>
public string Code { get; set; }
/// <summary>
/// 提示信息
/// </summary>
public string Message { get; set; }
/// <summary>
/// 成功或者失败
/// </summary>
public bool Success { get; set; }
/// <summary>
/// 返回结果,包含分页信息和实际数据列表
/// </summary>
public PageDataResult<T> Data { get; set; }
}
/// <summary>
/// 分页数据结果,包含分页相关信息和实际数据列表
/// </summary>
/// <typeparam name="T"></typeparam>
public class PageDataResult<T>
{
/// <summary>
/// 总记录数
/// </summary>
public int Records { get; set; }
/// <summary>
/// 当前页码
/// </summary>
public int PageIndex { get; set; }
/// <summary>
/// 每页大小
/// </summary>
public int PageSize { get; set; }
/// <summary>
/// 总页数
/// </summary>
public int TotalPage { get; set; }
/// <summary>
/// 实际数据列表
/// </summary>
public List<T> Datas { get; set; }
}
/// <summary>
/// 请求模型
/// </summary>
public class APIRequest
{
/// <summary>
/// 路由
/// </summary>
public string Route { get; set; }
/// <summary>
/// 请求方式
/// </summary>
public Method Method { get; set; }
/// <summary>
/// 参数
/// </summary>
public object Parames { get; set; }
/// <summary>
/// 发送数据类型。默认json
/// </summary>
public string ContentType { get; set; } = "application/json";
}
需要将帮助类 依赖注入容器
调用示例
一般请求接口
分页请求接口
七、使用LiveCharts组件库
1、安装插件LiveChartsCore.SkiaSharpView.WPF
页面上引用和使用线型图
这里我是绑定一直随机生成(其他使用方法要多看官网文档。基本上与echarts什么的没什么太多的区别)
代码
using LiveChartsCore.SkiaSharpView.Drawing.Geometries;
using LiveChartsCore.SkiaSharpView;
using LiveChartsCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LiveChartsCore.VisualElements;
using LiveChartsCore.SkiaSharpView.VisualElements;
using LiveChartsCore.SkiaSharpView.Painting;
using SkiaSharp;
using LiveChartsCore.Drawing;
using LiveChartsCore.SkiaSharpView.Drawing;
using LiveChartsCore.Defaults;
using System.Collections.ObjectModel;
namespace WpfDemo.ViewModels
{
public class LiveChartsDemo1UCViewModel : BindableBase
{
#region 1
//生成随机数
private readonly Random _random = new();
//图表数据来源
private readonly List<DateTimePoint> _values = [];
//X轴间隙
private readonly DateTimeAxis _customAxis;
//统计图表各个数据系列
public ObservableCollection<ISeries> Series { get; set; }
/// <summary>
/// x轴相关信息
/// </summary>
public Axis[] XAxes { get; set; }
/// <summary>
/// 处理多线程对同一资源访问,避免数据不一致冲突
/// </summary>
public object Sync { get; } = new object();
/// <summary>
/// 读取状态
/// </summary>
public bool IsReading { get; set; } = true;
public LiveChartsDemo1UCViewModel()
{
Series = [
new LineSeries<DateTimePoint>
{
Values = _values,
Fill = null,
GeometryFill = null,
GeometryStroke = null
}
];
_customAxis = new DateTimeAxis(TimeSpan.FromSeconds(1), Formatter)
{
CustomSeparators = GetSeparators(),
AnimationsSpeed = TimeSpan.FromMilliseconds(0),
SeparatorsPaint = new SolidColorPaint(SKColors.Black.WithAlpha(100))
};
XAxes = [_customAxis];
_ = ReadData();
}
private async Task ReadData()
{
while (IsReading)
{
await Task.Delay(100);
lock (Sync)
{
_values.Add(new DateTimePoint(DateTime.Now, _random.Next(0, 10)));
if (_values.Count > 250) _values.RemoveAt(0);
_customAxis.CustomSeparators = GetSeparators();
}
}
}
private static double[] GetSeparators()
{
var now = DateTime.Now;
return
[
now.AddSeconds(-25).Ticks,
now.AddSeconds(-20).Ticks,
now.AddSeconds(-15).Ticks,
now.AddSeconds(-10).Ticks,
now.AddSeconds(-5).Ticks,
now.Ticks
];
}
private static string Formatter(DateTime date)
{
var secsAgo = (DateTime.Now - date).TotalSeconds;
return secsAgo < 1
? "now"
: $"{secsAgo:N0}s ago";
}
#endregion
}
}
八、Material Designin 组件库使用
1、安装Material Designin组件
引用
可以去下载官网的项目后,到本地运行
https://github.com/MaterialDesignInXAML/MaterialDesignInXamlToolkit
查看使用示例
如:
这里可以看到各种需要的组件的使用方法
总结
提示:这里对文章进行总结: