DotNetNuke同一页面模块间数据传递:表单模块至按钮模块
在DotNetNuke同页面Tab内实现模块间数据传递
嘿,这种同页面多模块数据交互的场景在DNN开发里太常见啦,我给你整理几个实用的实现思路,你可以根据自己的需求选:
方案一:利用DNN官方内置的模块通信接口(IModuleCommunication)
这是DNN推荐的标准模块通信方式,适合结构化的数据传递:
让表单模块实现
IModuleCommunication接口
这个接口核心是SendMessage方法,用来主动向其他模块发送数据。示例代码:public class FormModule : PortalModuleBase, IModuleCommunication { // 实现接口方法,发送数据 public void SendMessage(string destinationModuleId, string message, object sender, Dictionary<string, object> additionalData) { // 打包表单数据,区分SectionA/SectionB var formData = new { Section = this.ModuleConfiguration.ModuleTitle, Data = GetFormData() }; additionalData.Add("FormData", formData); // 调用DNN通信机制发送消息 ModuleCommunication.SendMessage(this, destinationModuleId, "FormDataReady", additionalData); } // 自定义方法:获取表单数据 private YourFormModel GetFormData() { // 这里编写读取表单控件数据的逻辑 return new YourFormModel { /* 填充数据 */ }; } // 比如表单提交时触发数据发送 protected void btnSave_Click(object sender, EventArgs e) { // 按钮模块的ID可以通过配置项让管理员设置,这里先写死示例 string buttonModuleId = "123"; SendMessage(buttonModuleId, "FormDataReady", this, new Dictionary<string, object>()); } }让按钮模块实现
IModuleListener接口
这个接口用来监听其他模块的消息,重写OnMessageReceived接收数据:public class ButtonModule : PortalModuleBase, IModuleListener { private YourFormModel _sectionAData; private YourFormModel _sectionBData; protected override void OnInit(EventArgs e) { base.OnInit(e); // 注册监听,接收其他模块的消息 ModuleCommunication.RegisterListener(this); } // 接收消息的核心方法 public void OnMessageReceived(string message, Dictionary<string, object> additionalData, PortalModuleBase senderModule) { if (message == "FormDataReady") { var formData = additionalData["FormData"] as dynamic; if (formData.Section == "Section A") { _sectionAData = formData.Data; } else if (formData.Section == "Section B") { _sectionBData = formData.Data; } } } // 按钮点击时处理两个表单的数据 protected void btnProcess_Click(object sender, EventArgs e) { if (_sectionAData != null && _sectionBData != null) { // 这里编写你的数据处理逻辑,比如提交到数据库、生成报表等 } } }
方案二:利用页面级自定义事件共享数据
如果觉得官方通信机制有点重,这种方式更灵活,适合轻量交互:
在表单模块中定义自定义事件
先创建承载表单数据的事件参数类:public class FormDataEventArgs : EventArgs { public string SectionName { get; set; } public YourFormModel Data { get; set; } }然后在表单模块中暴露事件:
public class FormModule : PortalModuleBase { // 定义自定义事件,供其他模块订阅 public event EventHandler<FormDataEventArgs> FormDataReady; // 触发事件的封装方法 protected void RaiseFormDataReady() { var formData = GetFormData(); FormDataReady?.Invoke(this, new FormDataEventArgs { SectionName = this.ModuleConfiguration.ModuleTitle, Data = formData }); } // 页面加载完成后触发事件(或在表单提交时触发) protected void Page_PreRender(object sender, EventArgs e) { if (IsPostBack) { RaiseFormDataReady(); } } }在按钮模块中订阅表单模块的事件
在按钮模块的Page_Load中找到页面上的两个表单模块,订阅它们的事件:public class ButtonModule : PortalModuleBase { private YourFormModel _sectionAData; private YourFormModel _sectionBData; protected void Page_Load(object sender, EventArgs e) { // 遍历页面控件,找到所有表单模块实例 foreach (Control ctrl in Page.Controls) { if (ctrl is FormModule formModule) { if (formModule.ModuleConfiguration.ModuleTitle == "Section A") { formModule.FormDataReady += SectionA_DataReady; } else if (formModule.ModuleConfiguration.ModuleTitle == "Section B") { formModule.FormDataReady += SectionB_DataReady; } } } } private void SectionA_DataReady(object sender, FormDataEventArgs e) { _sectionAData = e.Data; } private void SectionB_DataReady(object sender, FormDataEventArgs e) { _sectionBData = e.Data; } // 处理数据的按钮逻辑 protected void btnProcess_Click(object sender, EventArgs e) { if (_sectionAData != null && _sectionBData != null) { // 执行你的业务逻辑 } } }
方案三:使用Session/ViewState临时存储数据
如果只是临时传递数据(不需要持久化),这种方式最简单直接:
表单模块存储数据到Session
protected void btnSubmit_Click(object sender, EventArgs e) { var formData = GetFormData(); // 用模块ID作为Session键,避免不同模块数据冲突 Session[$"FormData_{this.ModuleId}"] = Newtonsoft.Json.JsonConvert.SerializeObject(formData); }按钮模块读取Session中的数据
protected void btnProcess_Click(object sender, EventArgs e) { // 建议通过按钮模块的配置项获取两个表单的ModuleId,这里先写死示例 int sectionAModuleId = 123; int sectionBModuleId = 456; var sectionAJson = Session[$"FormData_{sectionAModuleId}"] as string; var sectionBJson = Session[$"FormData_{sectionBModuleId}"] as string; if (!string.IsNullOrEmpty(sectionAJson) && !string.IsNullOrEmpty(sectionBJson)) { var sectionAData = Newtonsoft.Json.JsonConvert.DeserializeObject<YourFormModel>(sectionAJson); var sectionBData = Newtonsoft.Json.JsonConvert.DeserializeObject<YourFormModel>(sectionBJson); // 处理数据 } // 处理完后清理Session,避免内存占用 Session.Remove($"FormData_{sectionAModuleId}"); Session.Remove($"FormData_{sectionBModuleId}"); }
注意事项
- 模块ID的灵活性:同页面的相同模块会有不同的
ModuleId,建议在按钮模块的设置页面添加配置项,让管理员手动输入两个表单模块的ID,避免硬编码。 - 数据序列化:推荐使用Newtonsoft.Json(DNN默认已引用)来序列化复杂对象,避免类型转换问题。
- 页面生命周期:如果是PostBack场景,要确保数据传递的时机正确(比如在
Page_Load之后、PreRender之前),避免出现数据未加载的情况。
内容的提问来源于stack exchange,提问作者Chan Yoong Hon
相关产品推荐
相关产品推荐

