简体   繁体   English

ASP.NET中动态呈现的用户控件的OnChange事件

[英]OnChange Events for Dynamically rendered User Controls in ASP.NET

I have a set of User controls shown in a Page (ABC.aspx) in 5 to 6 tabs. 我有一组显示在5至6个选项卡的页面(ABC.aspx)中的用户控件。 Each of the User control has many Textboxes, Drop Downs etc.. I need to detect any user changes on any of the fields in those user controls and do some processing on Parent page (ABC.aspx) on which these user controls reside. 每个用户控件都有许多文本框,下拉列表等。我需要检测这些用户控件中任何字段上的任何用户更改,并在这些用户控件所在的父页面(ABC.aspx)上进行一些处理。

The User Controls are implemented as follows. 用户控件的实现如下。 There is an XMl file for each of User controls which is read and creates controls accordingly. 每个用户控件都有一个XMl文件,该文件会被读取并相应地创建控件。

The render method in ascx.cs reads this xml file and renders the UI Acordingly for that User Control. ascx.cs中的render方法读取此xml文件并相应地为该用户控件呈现UI。

Lets say that sample XMl for a User control is 假设某个用户控件的示例XMl是

 <uigroup groupname ="Schematic(Logical) Symbol Request">
<uirow>
  <uicontrol displayname="Request Type" datatype="DropDown" isrequired="false" domainname="RequestType" dropdownEventHandler="OnScenarioChange(this)" key="Schematic Scenario" defaultValue="New"></uicontrol>
</uirow>
<uirow>
  <uicontrol displayname="Logical Name" datatype="TextBox" isrequired="false" supportedscenarios="New,Use Existing,Update Existing" key="Schematic Symbol Name"></uicontrol>
  <uicontrol displayname="Similar Symbol" datatype="TextBox" isrequired="false" supportedscenarios="New" key="Similar Schematic Symbol"></uicontrol>
</uirow>
<uirow>
  <uicontrol displayname="Type of Change" datatype="DropDown" isrequired="false" domainname="Type of Schematic Change" supportedscenarios="Update Existing" key="Type of Schematic Change"></uicontrol>
  <uicontrol displayname="Layout Preference" datatype="DropDown" isrequired="false" domainname="Schematic Layout Preference" supportedscenarios="New,Update Existing" key="Schematic Layout Preference"></uicontrol>
</uirow>
<uirow>
  <uicontrol displayname="Justification" datatype="DropDown" isrequired="false" domainname="Schematic Justification" supportedscenarios="Update Existing" key="Schematic Justification"></uicontrol>
  <uicontrol displayname="Logical Directory" datatype="DropDown" isrequired="false"   domainname="ICL Logical Directory" supportedscenarios="New" key="ICL Logical Directory"></uicontrol>
</uirow>

Usercontrol.ascx.cs has Usercontrol.ascx.cs具有

protected void Page_Load(object sender, EventArgs e)
    {
    }


    protected void Page_Init(object sender, EventArgs e)
    {
        this.Render();
    }

    public void Render()
    {
        this.Render(this.XmlPath);
    }

and my render function does the following 我的渲染函数执行以下操作

public void Render(string _filePath)
    {


        UITab tab = this.GetDataFromXML(_filePath);
        foreach (UIGroup g in tab.Groups)
        {
            //Add a panel
            Panel groupPanel = this.AddPanel(g);
            foreach (UIRow r in g.Rows)
            {
                Table table = new Table();
                groupPanel.Controls.Add(table);

                TableRow tableRow = new TableRow();
                table.Rows.Add(tableRow);

                foreach (UIControl c in r.Controls)
                {
                    switch (c.DataType)
                    {
                        case UIDataType.Textbox:
                            this.AddTextBox(groupPanel, c, tableRow);
                            break;
                        case UIDataType.Dropdown:
                            this.AddDropdown(groupPanel, c, tableRow);
                            break;
                        case UIDataType.LabelInfo:
                            this.AddLabelInfo(groupPanel, c,tableRow);
                            break;
                        case UIDataType.Label:
                            this.AddLabel(groupPanel, c,tableRow);
                            break;
                    }
                }
            }
        }
    }

We are rendering other user controls similar way. 我们正在以类似方式呈现其他用户控件。 we need to find a way to detect user changes on any of these user controls (like a text box changed or dropdown changed etc..) and do process the Parent page. 我们需要找到一种方法来检测这些用户控件中的任何用户控件的更改(例如,更改文本框或下拉菜单等),并处理“父”页面。

I am not sure if Delegates and Events might be a good fit and if yes, how would they fit in this architecture are my biggest questions here. 我不确定代表和活动是否合适,如果可以,它们在本体系结构中如何适应是我最大的问题。 Any constructive inputs would really help. 任何建设性的投入都将真正有帮助。

Thanks, 谢谢,

Yes, creating a custom event for your UserControl makes a lot of sense. 是的,为您的UserControl创建自定义事件很有意义。

Here's an example (note: the example shows the basic idea and does not use an XML document as a datasource; nonetheless, the example should be sufficiently instructive that you can apply it to what you've built): 这是一个示例(请注意:该示例显示了基本思想,并且未使用XML文档作为数据源;尽管如此,该示例应具有足够的指导意义,可以将其应用于已构建的内容):

Code for a simple User Control that dynamically injects nested controls: 用于动态注入嵌套控件的简单用户控件的代码:

...in the ascx file: ...在ascx文件中:

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="TabControl.ascx.cs" Inherits="StackOverflowAspNetQuestionAnswers.Controls.TabControl" %>
<asp:Panel ID="panel" runat="server">
</asp:Panel>

...in the code-behind file for the user control: ...在用户控件的代码隐藏文件中:

public partial class TabControl : System.Web.UI.UserControl
    {
        public event EventHandler<ControlChangedEventArgs> ControlUpdated;

        protected void Page_Load(object sender, EventArgs e)
        {
            TextBox textBox = new TextBox();
            textBox.AutoPostBack = true;
            textBox.ID = "textBox";

            textBox.TextChanged += textBox_TextChanged;

            DropDownList dropDown = new DropDownList();
            dropDown.Items.Add(new ListItem("Option 1", "Option 1"));
            dropDown.Items.Add(new ListItem("Option 2", "Option 2"));
            dropDown.AutoPostBack = true;

            dropDown.TextChanged += dropDown_TextChanged;

            panel.Controls.Add(textBox);
            panel.Controls.Add(dropDown);
        }

        void dropDown_TextChanged(object sender, EventArgs e)
        {
            ControlChangedEventArgs args = new ControlChangedEventArgs();

            args.ControlID = ((DropDownList)sender).ID;
            args.ControlValue = ((DropDownList)sender).SelectedValue;

            ControlUpdated(this, args);

            //CODE EDIT:
            UnhookEventHandlers();

        }

        void textBox_TextChanged(object sender, EventArgs e)
        {
            ControlChangedEventArgs args = new ControlChangedEventArgs();
            args.ControlID = ((TextBox)sender).ID;
            args.ControlValue = ((TextBox)sender).Text;
            ControlUpdated(this, args);

            //CODE EDIT:
            UnhookEventHandlers();

        }

        public virtual void OnControlUpdated(ControlChangedEventArgs e)
        {
            EventHandler<ControlChangedEventArgs> handler = ControlUpdated;
            if (handler != null)
            {
                handler(this, e);
            }

            //CODE EDIT:
            UnhookEventHandlers();

        }

        //CODE EDIT:
        private void UnhookEventHandlers()
        {
            foreach (var c in panel.Controls.OfType<DropDownList>())
            {
                c.TextChanged -= dropDown_TextChanged;
            }

            foreach (var c in panel.Controls.OfType<TextBox>())
            {
                c.TextChanged -= textBox_TextChanged;
            }
        }

    }

    public class ControlChangedEventArgs : EventArgs
    {
        public string ControlID { get; set; }
        public string ControlValue { get; set; }  
    }

Here's the code for the parent page that uses this simple tab control: 这是使用此简单选项卡控件的父页面的代码:

...in the .aspx file: ...在.aspx文件中:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="RaisingEventFromUserControl_Question.aspx.cs" Inherits="StackOverflowAspNetQuestionAnswers.RaisingEventFromUserControl_Question" %>

<%@ Register Src="~/Controls/TabControl.ascx" TagPrefix="uc1" TagName="TabControl" %>


    <!DOCTYPE html>

    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <asp:Label ID="message" runat="server" />
            <uc1:TabControl runat="server" id="TabControl" />
        </div>
        </form>
    </body>
    </html>

...in the code-behind file of the parent page: ...在父页面的代码隐藏文件中:

 public partial class RaisingEventFromUserControl_Question : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            TabControl.ControlUpdated += TabControl_ControlUpdated;
        }

        void TabControl_ControlUpdated(object sender, ControlChangedEventArgs e)
        {
           //EDIT: add code to update some data source to lock the form from other users
            message.Text = String.Format("A child control with an ID of '{0}' was updated. It now has the value of '{1}'.", e.ControlID, e.ControlValue);
        }
    }

As you can see in the example, I have a custom event named "ControlUpdated," which I fire anytime there is a change to either the nested TextBox or DropDownList that I dynamically inject into the UserControl at runtime. 如您在示例中看到的,我有一个名为“ ControlUpdated”的自定义事件,该事件在我对运行时动态注入到UserControl中的嵌套TextBox或DropDownList进行更改时都会触发。 Also, keep in mind that I set the "AutoPostBack" property for both the TextBox and DropDownList to ensure that the client-side code generated by ASP.Net executes whenever I change the value of the textbox / dropdown. 另外,请记住,我为TextBox和DropDownList都设置了“ AutoPostBack”属性,以确保每当我更改textbox / dropdown的值时,ASP.Net生成的客户端代码都能执行。

Also, you can see that for my custom event, I also created a custom EventArgs class so that I could pass along pertinent information from the nested control that is updated (that is, both the ID and the changed value). 此外,您可以看到,对于我的自定义事件,我还创建了一个自定义EventArgs类,以便可以传递来自已更新的嵌套控件的相关信息(即ID和更改后的值)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM