zoukankan      html  css  js  c++  java
  • [原创]FineUI秘密花园(二十八) — 窗体控件概述(下)

    本篇文章会继续讲解窗体控件的使用。

    表格与编辑窗体


    表格与编辑窗体的交互在项目中经常需要用到,为此FineUI专门为表格控件扩展了WindowField列,下面是一个典型的例子:

       1:  <ext:Grid ID="Grid2" Title="Grid2" PageSize="80" ShowBorder="false" AllowPaging="true"
       2:      OnPageIndexChange="Grid2_PageIndexChange" ShowHeader="False" runat="server" EnableCheckBoxSelect="True"
       3:      DataKeyNames="Id,Name" OnSort="Grid2_Sort" EnableRowNumber="True">
       4:      <Columns>
       5:          // 省略其他列...
       6:          <ext:WindowField TextAlign="Center" Width="60px" WindowID="Window1" Icon="Pencil"
       7:              ToolTip="编辑" DataIFrameUrlFields="Id,Name" DataIFrameUrlFormatString="../grid/grid_iframe_window.aspx?id={0}&name={1}"
       8:              Title="编辑" IFrameUrl="~/alert.aspx" />
       9:      </Columns>
      10:  </ext:Grid>
      11:                 
      12:  <ext:Window ID="Window1" Title="弹出窗体" Hidden="true" EnableIFrame="true" IFrameUrl="about:blank"
      13:      EnableMaximize="true" Target="Top" EnableResize="true" runat="server" OnClose="Window1_Close"
      14:      IsModal="true" Width="750px" EnableConfirmOnClose="true" Height="550px">
      15:  </ext:Window>


    表格控件WindowField列有如下属性需要特别关注:

    • WindowID:点击此字段弹出的窗体ID
    • DataIFrameUrlFields:绑定到窗体IFrame地址的字段名称列表
    • DataIFrameUrlFormatString:绑定到窗体IFrame地址的字段格式化字符串

    还有其他一些属性我们可能会用到:

    • UrlEncode:对每个绑定到IFrame地址的字段进行URL编码(默认为true)
    • DataWindowTitleField:绑定到窗体标题的字段名称
    • DataWindowTitleFormatString:绑定到窗体标题的字段格式化字符串
    • Enabled:是否可用(如果不可用,则会被渲染为静态文本)
    • IFrameUrl:窗体IFrame地址
    • Title:窗体标题
    • Icon:窗体图标
    • IconUrl:窗体图标地址

    其中UrlEncode属性用来对地址参数进行编码,比如本例中Major可能是“材料科学学院”,则生成的IFrame地址为 http://gsa.ustc.edu.cn/search?q=%E6%9D%90%E6%96%99%E7%A7%91%E5%AD%A6%E5%AD%A6%E9%99%A2

    如果作为IFrame地址的字段包含空格、中文或者其他特殊字符,则这个属性有助于生成浏览器可用的有效链接地址。


    Window控件需要特别注意的属性是EnableIFrame、IFrameUrl,如果需要在窗体关闭进行处理还需要注册OnClose事件处理函数(CloseAction属性的默认值是HidePostBack,不需要特别设置)。
    由于默认窗体IFrame中不需要加载任何页面,所以设置IFrameUrl为about:blank.


    弹出编辑窗体时的界面效果:

    image

    子窗体与父窗体传值


    这里的子窗体指的是包含IFrame的弹出子窗体,由于子窗体包含的页面和父窗体属于两个不同的页面,这就涉及Asp.Net两个页面如何传值的问题。

    • 父页面向子页面传值:这个比较简单,一般通过地址栏参数传递,比如父页面是列表页面list.aspx,编辑某一条目时地址为edit_item.aspx?id=322
    • 父页面向子页面传值:
      • 临时Session,在关闭子页面之前,将要保存的数据存入Session中,Session("edit_result1") = "1111";  然后在父页面中获取此保存的值(需要刷新或者回发父页面)Session("edit_result1").ToString()
      • 临时Cookie,方法同Session,只不过Cookie是将数据保存在客户端而不是服务器,但是有大小限制
      • JavaScript传值,其实临时Session和临时Cookie都不是好的解决办法,不仅性能有问题而且编码复杂。由于子页面和父页面位于相同的域名下(不违反JavaScript的同源策略),所以可以直接在子页面中查找父页面的表单字段,并将结果保存到父页面的表单字段中。

    FineUI充分理解这种需求,并提供了方便的函数来帮助我们在父窗体向子窗体传值,大致步骤如下:

    1. 告诉子窗体,父窗体中可以被作为接受结果数据的表单字段有哪些
    2. 打开子窗体
    3. 用户操作后得到结果,将结果保存到父窗体中接受数据的表单字段
    4. 关闭子窗体

    下面通过一个示例来认识这一过程:

    父页面代码:

       1:  <ext:SimpleForm ID="SimpleForm1" Title="表单" EnableBackgroundColor="true" BodyPadding="5px"
       2:      runat="server" Width="500px" EnableCollapse="True">
       3:      <Items>
       4:          <ext:TextBox Label="你所在的省份" ID="TextBox1" runat="server">
       5:          </ext:TextBox>
       6:          <ext:Button ID="Button1" EnablePostBack="false" runat="server" Text="从列表中选择">
       7:          </ext:Button>
       8:      </Items>
       9:  </ext:SimpleForm>
      10:   
      11:  <ext:Window ID="Window1" Title="编辑" Popup="false" EnableIFrame="true" runat="server"
      12:      EnableMaximize="true" EnableResize="true" Target="Parent" OnClose="Window1_Close"
      13:      IsModal="True" Width="750px" Height="450px">
      14:  </ext:Window>

     

       1:  protected void Page_Load(object sender, EventArgs e)
       2:  {
       3:      if (!IsPostBack)
       4:      {
       5:          Button1.OnClientClick = Window1.GetSaveStateReference(TextBox1.ClientID)
       6:              + Window1.GetShowReference("./passvalue_iframe_iframe.aspx");
       7:      }
       8:  }
       9:   

    界面效果:

    image


    子页面代码:

       1:  <ext:SimpleForm ID="SimpleForm1" ShowBorder="false" ShowHeader="false" Title="SimpleForm"
       2:      EnableBackgroundColor="true" BodyPadding="5px" runat="server" EnableCollapse="True">
       3:      <Items>
       4:          <ext:DropDownList ID="ddlSheng" Label="请选择省份" ShowRedStar="true" runat="server" AutoPostBack="true"
       5:              OnSelectedIndexChanged="ddlSheng_SelectedIndexChanged">
       6:          </ext:DropDownList>
       7:      </Items>
       8:  </ext:SimpleForm>
       1:  protected void Page_Load(object sender, EventArgs e)
       2:  {
       3:      if (!IsPostBack)
       4:      {
       5:          BindSheng();
       6:      }
       7:  }
       8:   
       9:  private void BindSheng()
      10:  {
      11:      ddlSheng.DataSource = SHENG_JSON;
      12:      ddlSheng.DataBind();
      13:   
      14:      ddlSheng.Items.Insert(0, new ListItem("选择省份", "-1"));
      15:  }
      16:   
      17:  protected void ddlSheng_SelectedIndexChanged(object sender, EventArgs e)
      18:  {
      19:      if (ddlSheng.SelectedValue != "-1")
      20:      {
      21:          PageContext.RegisterStartupScript(ActiveWindow.GetWriteBackValueReference(ddlSheng.SelectedValue) + ActiveWindow.GetHideReference());
      22:      }
      23:  }

    对比前面介绍的四个步骤,我们来看下分别对应的代码:

    1. 告诉子窗体,父窗体中可以被作为接受结果数据的表单字段有哪些:Window1.GetSaveStateReference(TextBox1.ClientID)
    2. 打开子窗体:Window1.GetShowReference("./passvalue_iframe_iframe.aspx")
    3. 用户操作后得到结果,将结果保存到父窗体中接受数据的表单字段:ActiveWindow.GetWriteBackValueReference(ddlSheng.SelectedValue)
    4. 关闭子窗体:ActiveWindow.GetHideReference()

    在子窗体的下拉列表中选择“安徽”后,子窗口关闭并返回父页面:

    image

    image

    注意:GetSaveStateReference 和GetWriteBackValueReference有重载方法,可以一次传入多个表单字段,参考示例

    回发父页面

    通过前面的学习,我们知道了如何是在子窗体(内嵌IFrame)关闭时回发父页面。但是对于如下两个需求,该如何实现呢?

    1. 不关闭子窗体(内嵌IFrame)的情况下回发父页面;
    2. 内嵌IFrame的面板中回发父页面。

    下面通过一个示例来展示如何处理第二种情况,先看下最终的页面效果:

    image

    这个页面的标签定义如下:

       1:  <ext:PageManager ID="PageManager1" runat="server" />
       2:  页面一:parent_simplepostback.aspx
       3:  <ext:Label ID="labResult" runat="server">
       4:  </ext:Label>
       5:  <br />
       6:  <br />
       7:  <ext:Panel ID="Panel1" runat="server" EnableBackgroundColor="true" ShowBorder="true"
       8:      Width="400px" Height="250px" EnableIFrame="true" IFrameUrl="parent_simplepostback2.aspx"
       9:      ShowHeader="true" Title="面板一">
      10:  </ext:Panel>

    后台代码:

       1:  protected void Page_Load(object sender, EventArgs e)
       2:  {
       3:      if (IsPostBack)
       4:      {
       5:          if (Request.Form["__EVENTARGUMENT"] == "param_from_simplepostback2")
       6:          {
       7:              Alert.Show("来自子面板IFrame中的事件!");
       8:          }
       9:      }
      10:   
      11:      labResult.Text = "页面加载时间:" + DateTime.Now.ToLongTimeString();
      12:  }

    特别注意:和我们通常看到的 if(!IsPostBack) 不同,这里的逻辑是在页面回发时判断事件参数是否为 param_from_simplepostback2 (而不管事件来源是哪个控件,实际上从后面的代码可以明显看出,这个事件的来源为空,是由子页面手工触发的)。

    点击回发父页面时的界面显示:

    image

    那么,点击此按钮的逻辑该如何处理呢?

       1:  protected void Button1_Click(object sender, EventArgs e)
       2:  {
       3:      PageContext.RegisterStartupScript("parent.__doPostBack('','param_from_simplepostback2');");
       4:  }

    其实就是调用父页面的 __doPostBack 函数,指定此次回发事件的事件源为空,事件参数为 param_from_simplepostback2。

    小结

    窗体控件在实际项目中使用非常广泛,特别是和表格控件一起提供的新增、编辑等功能。同时本章还详细描述了如何实现子窗体和父页面的传值问题,在实际项目中也有广泛的应用。

    注:《FineUI秘密花园》系列文章由三生石上原创,博客园首发,转载请注明出处。文章目录 官方论坛

  • 相关阅读:
    centos7物理机a start job is running for dev-mapper-centosx2dhome.device
    jenkins pipeline流水线
    nginx 加载慢 负载均衡不均衡
    山田预发环境发布脚本
    prometheus 监控容器
    maven私服安装使用
    日志清理
    ERROR 1046 (3D000) at line 1: No database selected
    网络工程学习经典书籍推荐
    每日一句
  • 原文地址:https://www.cnblogs.com/sanshi/p/2847102.html
Copyright © 2011-2022 走看看