栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

AppBox v6.0中实现子页面和父页面的复杂交互

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

AppBox v6.0中实现子页面和父页面的复杂交互

前言

1. 你可以通过捐赠获取 AppBox 的完整源代码:http://fineui.com/donate/

2. AppBox v3.0于 2013-08 发布,采用了EF CodeFirst开发模式和扁平化的设计理念:http://www.cnblogs.com/sanshi/p/3274122.html

 

AppBox v3.0中的子页面向父页面传值

AppBox中实现子页面向父页面传值,逻辑代码比较简单,完全使用FineUI的内置封装,没有引入Javascript代码。首先来看下实现效果:

当点击所属角色的触发器输入框(TriggerBox)时,会在当前页面弹出一个包含Iframe的窗体控件(Window),在其中选择需要的数据后关闭。

 

父页面代码和逻辑

在父页面,我们通过一个 TriggerBox 来记录选中的文本信息,一个隐藏字段 HiddenField 来记录选中的值信息:

 

点击 TriggerBox 触发图标的客户端操作是通过服务器端初始化的,这其实是符合FineUI最初的设计目标:尽量减少客户端脚本,降低代码复杂度。

private void InitUserRole(User current){    tbSelectedRole.Text = String.Join(",", current.Roles.Select(u => u.Name).ToArray());    hfSelectedRole.Text = String.Join(",", current.Roles.Select(u => u.ID).ToArray());    // 打开编辑角色的窗口    string selectRoleURL = String.Format("./user_select_role.aspx?ids=", hfSelectedRole.GetValueReference());    tbSelectedRole.OnClientTriggerClick = Window1.GetSaveStateReference(hfSelectedRole.ClientID, tbSelectedRole.ClientID)            + Window1.GetShowReference(selectRoleURL, "选择用户所属的角色");}

 

仔细观察这段代码,可以看到FineUI的努力和身影,我们尽量将常用操作提取成公共的方法。

比如这里的:

hfSelectedRole.GetValueReference()

则是返回一段Javascript脚本,本质上点击操作是客户端完成的,因此需要在点击的时候获取隐藏输入框的值,而不是调用InitUserRole初始化的时候!!

再比如这里:

Window1.GetSaveStateReference(hfSelectedRole.ClientID, tbSelectedRole.ClientID)

这是FineUI提供的另一个机制:告诉FineUI子页面回发数据时,需要将数据保存到父页面的哪些控件中?

 

子页面代码和逻辑

看完父页面的代码,再来看下子页面怎么返回值。首先,子页面有一个选择的按钮,和一个复选框列表控件:

 

点击按钮会触发一个服务器端事件:

protected void btnSaveClose_Click(object sender, EventArgs e){    string rolevalues = String.Join(",", cblRole.SelectedItemArray.Select(c => c.Value));    string roleTexts = String.Join(",", cblRole.SelectedItemArray.Select(c => c.Text));    PageContext.RegisterStartupscript(ActiveWindow.GetWriteBackValueReference(rolevalues, roleTexts)        + ActiveWindow.GetHideReference());}

首先获取复选框列表中,用户选择的文本信息和值信息,然后通过 PageContext.RegisterStartupscript 向子页面注册一段脚本。

 

在内部FineUI其实隐藏了很多复杂的逻辑:

1. 弹出窗体可以在父页面弹出,可以在父页面的父页面弹出,也可以在顶层页面弹出。

2. 如果在子页面最快的找到我们所说的父页面,而不是window.parent!!,这里FineUI封装了一个ActiveWindow类。

 

ActiveWindow表示的是当前激活的窗体(也就是我们所说的子页面Iframe所在的Window控件),用来联系业务逻辑上的子页面和父页面。

ActiveWindow.GetWriteBackValueReference(rolevalues, roleTexts)

这段代码和前面的 GetSaveStateReference 相对应,用来将用户选择的值写入父页面相应的控件中。

 

至此,我们没写一行Javascript代码,实现了子页面向父页面传值这个本来需要Javascript交互的示例。

 

 

AppBox v6.0中的子页面和父页面的复杂交互

首先一点声明,AppBox v6.0虽然和 v3.0版本号变化很大,但是代码改变并不多,主要是为了跟着 FineUI(开源版)的版本走。

 

AppBox v6.0中,我们首先想做的一点改变是:为选择角色的触发器输入框增加清空图标!!

 

看下最后的实现效果:

之所以放了 5 张图在这里,是因为这是FineUI(开源版)v6.0.0中内置的 5 种主题。

 

看似一个简单的改变,其实一点都不简单,因为在子页面传值这个已有逻辑基础上,还要进行清空图标是否可见的逻辑改变:

1. 默认如果所属角色存在值,则显示清空图标;否则不显示清空图标

2. 点击清空图标时,清空两个控件的值,然后隐藏清空图标

3. 从子页面返回数据时,需要显示清空图标

由于存在这些逻辑,FineUI内置的服务器端做法已经满足不了需求了。因为我们决定自己写Javascript代码来实现。

 

父页面代码和逻辑

首先是将 TriggerBox 改为 TwinTriggerBox 控件,并在客户端实现两个触发图标的点击操作:

默认是不显示清空图标的,所以需要在页面加载完毕后,进行逻辑判断:

var tbSelectedRoleClientID = '<%= tbSelectedRole.ClientID %>';var hfSelectedRoleClientID = '<%= hfSelectedRole.ClientID %>';function checkSelectedRoleTriggerStatus() {    if (F(tbSelectedRoleClientID).getValue()) {        F(tbSelectedRoleClientID).showTrigger1();    } else {        F(tbSelectedRoleClientID).hideTrigger1();    }}F.ready(function () {    checkSelectedRoleTriggerStatus();});

 

然后再来看下点击两个触发图标的操作:

function onSelectedRoleTrigger1Click() {    F(tbSelectedRoleClientID).setValue('');    F(hfSelectedRoleClientID).setValue('');    checkSelectedRoleTriggerStatus();}function onSelectedRoleTrigger2Click() {    F('Window1').f_show(F.baseUrl + 'admin/user_select_role.aspx?ids=' + F(hfSelectedRoleClientID).getValue() + '', '选择用户所属的角色');}

点击第二个触发按钮时,会弹出包含Iframe页面的Window控件,并向Iframe地址传入角色值信息。

 

同时,我们还需要一个函数供子页面调用(更新用户所属角色的两个控件值):

function updateSelectedRole(roleNames, roleIds) {    F(tbSelectedRoleClientID).setValue(roleNames);    F(hfSelectedRoleClientID).setValue(roleIds);    checkSelectedRoleTriggerStatus();}

 

子页面代码和逻辑

子页面点击选择按钮时,所有代码逻辑在客户端完成,这样也减少了一个HTTP回发:

                

在客户端脚本,我们需要完成几个逻辑:

1. 通过Javascript代码获取复选框列表的文本和值信息

2. 获取对应的业务父页面(不是window.parent!!)

3. 调用父页面的 updateSelectedRole 函数

4. 关闭弹出窗体

 

下面来看下实现代码,还是很清晰的:

var cblRoleClientID = '<%= cblRole.ClientID %>';function onSaveCloseClick() {    // 数据源 - 复选框列表    var cblRole = F(cblRoleClientID);    var roleNames = [], roleIds = [];    cblRole.items.each(function (item) {        // 是否选中        if (item.getValue()) {            roleNames.push(item.boxLabel);            roleIds.push(item.inputValue);        }    });    // 返回当前活动Window对象(浏览器窗口对象通过F.getActiveWindow().window获取)    var activeWindow = F.getActiveWindow();    activeWindow.window.updateSelectedRole(roleNames, roleIds);    activeWindow.f_hide();}

获取复选框列表的值,用到了 extjs 公开的API接口,不难。

 

而获取业务父页面就不那么简单了,原因前面已经提到了,要特别注意,这个业务父页面不是window.parent!!!!

FineUI也提供了相应的客户端接口:

1. F.getActiveWindow() 获取子页面所在的Window服务器控件对象(不是JS的window对象)

2. F.getActiveWindow().window 获取业务父页面所在的window对象(注意不是Window服务器控件)

理解这两个接口后,就简单了,调用父页面定义的 updateSelectedRole 函数:

F.getActiveWindow().window.updateSelectedRole(roleNames, roleIds);

 

小结

通过本篇文章的介绍,我们知道了如何不写一行Javascript代码来实现子页面向父页面传值。而对于复杂的交互逻辑,我们也可以手工写Javascript代码来实现。

由于子页面在作为Iframe放在Window控件中的,而Window控件可以在父页面弹出、可以在父页面的父页面弹出,也可以在顶层页面弹出,这就让如何在子页面中获取业务父页面变得扑所迷离(不是window.parent!),幸运的是FineUI对此提供了服务器端支持(ActiveWindow类)和客户端的支持(F.getActiveWindow函数)。

 

关于开源和坚持

AppBox作为FineUI(开源版)的一个演示项目,从 2009 年就一直存在了,期间经历了 v3.0 的大版本更新,其他版本的改动都不多。但是我们一直在更新FineUI(开源版)和AppBox,至今已经有 8 年时间了。

8 年间,我们看过太多的开源项目轰轰烈烈的来,平平淡淡的去,那些曾经熟悉的身影,曾经陪伴我们的代码,都已经不复存在。其实很多时候,开源项目不是被新技术淘汰,而是被开源作者所丢弃,不免让人扼腕叹息。

每个存在都有存在的价值,时间总会让之前的东西看起来不再那么新奇好玩,但是还有那么一帮曾经关注的网友,一直在使用的用户,只有不断的更新,才不会让关心你的人失望。

 

任何事物的存在价值是无限的!

 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/231717.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号