• FineUIMvc随笔(5)UIHelper是个什么梗?


    声明:FineUIMvc(基础版)是免费软件,本系列文章适用于基础版。

    UIHelper.Result

    在 FineUIMvc 的每一个 HttpPost 的控制器方法里面,你都会看到 UIHelper.Result():

    这到底是个什么梗?在 ASP.NET MVC 中并没有 UIHelper 这样一个静态类,为何它能频频出现于每个 HttpPost 的控制器方法中呢?

    这一切的一切还要从 ActionResult 入手。

    ActionResult

    即使第一天接触 ASP.NET MVC 开发人员也应该知道 ActionResult 的含义,作为控制器方法(Action)的返回值(Result),这是一个抽象类。

    MVC 内置了很多 ActionResult 的实现类,最常用的可能是下面几个:

    1. ViewResult:返回视图。

    2. ContentResult:返回一个静态字符串。

    3. RedirectResult:重定向到另一个URL,类似于 WebForms 中的 Response.Redirect 函数,返回的HTTP状态码是 302 Redirect。

    4. JsonResult:返回一个JSON字符串。

    5. HttpNotFoundResult:未找到对象,一般用于URL参数错误,返回的HTTP状态码是 404 Not Found。

    还有很多类似的实现,在学习过程中我们会逐步接触。

    但是这里面没有 FineUIMvc 回发时能用的 ActionResult,如果你之前对 FineUI(开源版)有所了解的话,就知道 FineUI 回发时返回的是一串 JavaScript 代码:

    因此我们就需要自定义 ActionResult 的实现类,来在 FineUIMvc 回发时返回需要的 JavaScript 代码,这个实现类就是 FineUIMvc.AjaxResult。

    FineUIMvc.AjaxResult 会处理回发过程中每个控件的改变,并转化为 JavaScript 代码并返回。

    比如这样一段 C# 代码:

    Alert.Show("你好 FineUIMvc!", MessageBoxIcon.Warning);

    在返回的 HTTP 响应中,对应于:

    F.alert({message:'你好 FineUIMvc!',messageIcon:'warning'});

    这个转化过程就是有 FineUIMvc.AjaxResult 类负责的。

    而 UIHelper.Result 就是返回的一个 AjaxResult 实例,内部实现如下:

    public static class UIHelper
    {
        
        /// <summary>
        /// 响应Ajax请求
        /// </summary>
        /// <returns></returns>
        public static AjaxResult Result()
        {
            return new AjaxResult();
        }
        
    }

    现在回过头来,我们看下 ASP.NET MVC 中的 HttpPost 控制器方法中为啥不需要类似 AjaxResult 的实现:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create([Bind(Include = "ID,Name,Gender,Major,EntranceDate")] Student student)
    {
           if (ModelState.IsValid)
           {
                  db.Students.Add(student);
                  db.SaveChanges();
                  return RedirectToAction("Index");
           }
     
           return View(student);
    }

    可以看到,原生的 HttpPost 控制器方法直接返回的是视图(ViewResult的实例),也就是整个页面的更新,非AJAX过程。

    UIHelper.Button,UIHelper.Grid,UIHelper.Tree... 

    UIHelper 还有一个重要的用途,那就是根据控件的 ID 获取控件对象,并对其进行更改,UIHelper.Result 会将所有的更改转化为 JavaScript 并返回到客户端。

    下面通过一个例子来详细说明这一过程:

    在线示例地址:http://fineui.com/demo_mvc#/demo_mvc/Button/Button

    在这个例子中,点击第一个按钮,会不断切换第二个按钮[按下的按钮]的状态,第一个按钮的点击事件处理函数:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult btnChangePressed_Click(bool pressed)
    {
        UIHelper.Button("btnPressed").Pressed(!pressed);
    
        return UIHelper.Result();
    }

    这里面有几个重要的概念:

    1. 第二个按钮的当前状态需要通过客户端传入,服务器端对其一无所知(从 WebForms 转入的开发人员常常会忽略这个重要概念)。

    2. UIHelper.Button("btnPressed"),用来返回一个 ID 为 btnPressed 的按钮示例。

    3. Pressed 方法用来生成一段改变按下状态的脚本。

    一个常常令开发人员疑惑的事实是:UIHelper.Button("btnPressed") 返回的并不是你在 View 中定义的名为 btnPressed 的按钮对象!

    因为 HTTP 协议本身是无状态,因此服务器端不可能知道客户端的任何数据(除非你显式传入的数据),更无法得知你在 View 中定义的任何内容了。

    是不是怀念 WebForms 了,因为在 WebForms 中 ViewState 帮你记下了所有的控件属性,然而你不是很讨厌 ViewState 的臃肿吗?

    让我来做个简单的说明,希望能解开你心中的疑惑,在 View 中,我们是这么定义按钮的:

    @(F.Button()
        .ID("btnPressed")
        .Text("按下的按钮")
        .EnablePress(true)
        .Pressed(true)
    )

    在回发里面,如果你试图获取按钮的 Text 属性,你会发现这个是空字符串!

    UIHelper.Button("btnPressed").Source.Text

    因为在 FineUIMvc 内部,只是重新创建了一个 ID=btnPressed 的按钮,默认按钮的 Text 就是空字符串。

    为了尽量避免开发人员犯这个错误,所有 UIHelper.Button, UIHelper.Grid... 返回实例中,只能通过方法来操作,比如更改按钮的显示文本:

    UIHelper.Button("btnPressed").Text("修改成你想要的文本");

    再次强调:UIHelper.Button 返回的是按钮示例只是用来辅助生成前端 JavaScript 的更新脚本,不是 View 中定义的按钮实例。

    下面简单看下,在前台如何传入第二个按钮的按下状态:

    @(F.Button()
        .ID("btnChangePressed")
        .Text("改变后面按钮的按下状态")
        .CssClass("marginr")
        .OnClick(Url.Action("btnChangePressed_Click"), new Parameter("pressed", "F.ui.btnPressed.isPressed()"))
    )

    通过上一篇文章讲解的自定义参数,我们知道 Paramter 示例中的第二个参数是一段 JavaScript 代码:

    F.ui.btnPressed.isPressed()

    小结

    UIHelper 是一个非常重要的静态类,它有两个主要的用途。

    UIHelper.Result 用来返回一个 FineUIMvc.AjaxResult 的实例,用来将回发时的更改转化为 JavaScript 代码返回。

    另一个重要用途的返回控件实例(比如 UIHelper.Button,UIHelper.Grid,UIHelper.Tree...),并提供一系列的方法来更新控件,但是要注意这里的控件实例并不是你在 View 中定义的那个实例,只是一个新创建的同名实例而已,方便更新控件属性。

    《FineUIMvc随笔》目录:http://www.cnblogs.com/sanshi/p/6473592.html 

  • 相关阅读:
    客户端用mstsc不能用一台设备连接终端服务器的解决办法
    [转]知识管理ABC
    Visual Studio常用小技巧[备忘]
    一套外企的数据库设计面试题
    MSDN中的图形元素和文档约定[备忘]
    设计模式概述
    ASP.Net 4.0中新增加的23项功能[转]
    Dreamweaver 8 的相关使用
    浅谈ThreadPool 线程池
    C#委托的异步调用[学习]
  • 原文地址:https://www.cnblogs.com/sanshi/p/6500955.html
Copyright © 2020-2023  润新知