编辑
2024-07-19
我当开发
00

目录

1. 理论 🤔
2. 问题 💭
3. 部分代码

FineUI初学手册中提到FineUICoreWebForms 会将页面状态全部回发,后台解析后实现后台得到前台的数据;

之前我还提到过使用SignalR.InvokeAsync来执行js收集前台的信息;

结合以上两点💡,在开发中我使用 FineUICoreMVC 实现了在Controller中对前端控件状态的获取🛠️,从而减少前台js的代码,让后台方法看起来更加完整📝;

FineUIAjaxHelpEx设计.drawio.png

1. 理论 🤔

MVC中 Controller.cs文件并不能直接⚡️获得前台控件的状态,只能通过前台的收集后回发🔙给后台;在传统的MVC开发中这种方式是被推荐的,具体的方法接收参数,不关心参数值😑的来源,保证了职责的单一性和复用性;这样写也有坏处就是当方法需要接收其他参数时,我需要同时修改提交的js和接收的方法;

其实FineUICore中的Controller职责和cshtml的职责差不多,需要收集和处理前台的信息,最后处理后的信息也是通过响应js来实现的;所以FineUICore中的Controller我完全可以考虑负责收集页面📊的数据,让数据的收集和处理统一在一个方法中;

///改进前 [HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> OnSaveBtnClick(MsOAR_A1 ms) { awati bll.Save(ms); } ///改进后 public async Task<IActionResult> OnSaveBtnClick() { MsOAR_A1 ms = await Form1.GetData(); awati bll.Save(ms); }

在上面提到过,SignalR.InvokeAsync 可以实时的和前台交互拿到数据,所以没有必要将全部的信息都回发🔄再转为控件模型;可以直接实时拿数据;

2. 问题 💭

理论跑通后我结合现有的框架进行了实践,大致的路径如下

这里需要考虑的问题就是 虽然 SignalR.InvokeAsync 可以执行js 比如 return F.ui.Form1.getdata(); 但是这里的SignalR事件监听应该写在哪,这里的Form1控件明显是在回发的那个页面,执行这段js也应该在这个页面;在框架下可能打开了多个页面,或者弹出的窗口,所以要找到当前回发页面,需要标识;

这里有两个办法,

  • 一个是 当页面打开时,前台注册SignalR事件监听,事件名称唯一,回发时带着这个事件名称,后台执行InvokeAsync指定事件事件名称然后执行js;
  • 另一个方法是 当回发时回发本次提交的唯一标识,并将当前的页面和唯一标识绑定,当后台执行InvokeAsync时执行通用的事件,通过唯一标识找到页面,然后执行js;

我选择了第二个方法,这样改动量会小一些;

3. 部分代码

对于简单的交互,省去了大部分js代码

cshtml
.Items( F.Button().ID("btnsave").BtnType(FineUIEx.BtnTypes.保存) .OnClickAsync("OnOARA1Save",autoLoading: "btnsave,btnclear"), F.Button().ID("btnclear").BtnType(FineUIEx.BtnTypes.取消) .Text("清除").OnClickAsync("OnOARA1Delete", autoLoading: "btnsave,btnclear") )),
Controller
[HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> OnOARA1Save() { //得到数据 var msa1 = await Form1.GetData<MsOAR_A1>(true); if (msa1 != null) { //保存 var rt = await bLLOARA1.Save(msa1); //提示 ShowNotify(Convert.ToInt32(rt.strMsId) >= 0 ? "保存成功" : rt.strMS); //重置ID Form1.SetData(new { OAR_A1_AUTOID = rt.strMsId }, true); //刷新列表 await InitData(); } return ResultAsync(); }

JSHandle
window.top.PostWindow = {}; //处理fineui的ajax window.top.hub.connection.on(`JSHandle`, async (msg) => { let { postGUID, fun } = JSON.parse(msg); //这里要通过postGUID找到页面 拿到结果后要删除 let page = window.top.PostWindow[postGUID]; let res = (page.Function(fun))(); return res; });
JSHandle
//执行JS public static async Task<string> GetHubMessage(string fun) { if (!string.IsNullOrEmpty(fun)) { if (!fun.Trim().StartsWith("return")) { fun = "return " + fun; } //尝试拿一个hubid string evname = "JSHandle"; //本地提交的ID var postGUID = string.Empty; var Form = FineUICore.PageContext.Current.Request.Form; if (Form.ContainsKey("postGUID")) { postGUID = Form["postGUID"]; } //终端ID var id = SignalRHelper.GetHubID(); if (string.IsNullOrEmpty(id) || string.IsNullOrEmpty(postGUID)) { return ""; } var json = JObject.FromObject(new { postGUID, fun }).ToString(); var Hub = PageContext.GetServerByApp<IHubContext<SignalRHub>>(); var msr = await Hub.Clients.Client(id).InvokeAsync<System.Text.Json.JsonElement>(evname, json, new CancellationToken()); return GetValueAsString(msr); } return ""; }

常用的取值,表单值,列表选择行,输入框取值都做了扩展;

FormAjaxEx
using FineUICore; namespace HD.UIControl.FineUIBase { public static class FormAjaxEx { /// <summary> /// 得到数据 /// </summary> /// <param name="f"></param> /// <param name="isv">是否验证数据</param> /// <returns></returns> public static async Task<JObject> FGetData(this string f, bool isv = false) { fields ??= Array.Empty<string>(); var fun = $" return F.ui['{f}'].getdata({isv.ToString().ToLower()});"; var res = await FineUIAjaxHelpEx.GetHubMessage(fun); return JToken.Parse(res) is JObject obj ? obj : default; } } }

如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:没想好

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!