【问题标题】:The correct pattern for passing data to child controls in a server control将数据传递给服务器控件中的子控件的正确模式
【发布时间】:2010-11-09 17:29:36
【问题描述】:

我正在使用第 3 方系统在网站中实现某些表单。

第 3 方系统为我提供了这些表单的 XML 定义。 例如

<form>
    <segment>
        <label>The header</label>
        <fields>
            ...
            <field>
                <id>field_Dob</id>
                <type>Date</type>
                <label>Date of Birth</label>
                <required>1</required>
            </field>
            ...
        </fields>
    </segment>
    ...
</form>

我在服务器控件中解析此 XML 并以编程方式生成控件树。控件的标签在 XML 中传递。

在此表单中“注入”小帮助文本是我们建议的一部分。

理想情况下,我想从顶级控件的标记中传递这些帮助文本,以便非开发人员(HTML 僧侣)可以更改帮助文本,并通过其 ID 将它们与字段相关联。像这样的

<controls:MyCrazyForm runat="server">
    <helpTexts>
        <helpText for="field_Dob">
Some rambling nonsense to do with the DOB field
        </helpText>
        ...
    </helpTexts>
</controls:MyCrazyForm>

这些控件被递归解析。

表单为每个段创建一个字段集,字段集根据数据类型创建许多 FieldXXX(其中 XXX = 日期、文本、组合框等)。

FieldXXX 类型创建一个 div,然后创建几个标准的 .net 控件(TextBox、DropDownList 等)来实际呈现它们自己。此时,我需要在包含的 div 中输出帮助文本。

我的问题

将这些文本从顶级表单控件获取到控件树中更深 3 或 4 级的子控件的“最佳”方法是什么。

页面上只会有这些表单之一。 我应该将顶级表单设为 Singleton 并像这样得到它吗?

if(MyCrazyForm.Instance.HelpTexts.ContainsKey("theIdOfTheCurrentField"))
{
    this.HelpText = MyCrazyForm.Instance.HelpTexts["theIdOfTheCurrentField"];
}

我是否应该将表单的引用传递到树下的每个控件(这看起来很乱)?

我的 架构 是否已经达到目标(尽管目前它工作得很好)形式,我应该看看不同的实现方法吗?

谢谢

【问题讨论】:

    标签: c# asp.net .net-3.5 servercontrols


    【解决方案1】:

    如何向上遍历控件的父控件,直到找到某个类型的控件,或者找到一个名为“HelpTexts”的特定成员变量?

    这是一种动态编程方法,但对于某些设计的基础设施元素,只要此类方法受到限制,并且对采用该设计方法的原因进行了充分评论,我认为它是可以接受的。

    这将是使用反射 API 和通用静态辅助函数,例如

    GetHelpTextFromParent(Control controlParent, string id)
    

    然后这将检查 controlParent 以查看其中是否包含成员变量 HelpTexts,然后通过 id 查找帮助文本。如果不是,它将递归调用 GetHelpTextFromParent 与 controlParent 的父级,直到合适的终止条件。 (我提到“合适的终止条件”,因为在您到达桌面窗口之前保持这种状态可能不是最理想的,您可能希望在此之前终止递归,但这将是一个测试/调试问题。)

    【讨论】:

      【解决方案2】:

      如果您在服务器控件中解析此 XML 并以编程方式生成控件树您如何确保 HTML 人员保持这些 ID 同步?如果他们有权访问这些 XML,也许您应该让他们在此处添加 helpTexts,而不是在 aspx 上。

      但要回答您的问题,我想您是在读取和构建 aspx 标记之后解析 xml,这样您就可以在解析 XML 之前对这些文本进行索引。然后,当您实际构建动态控件树时,您可以通过源 xml 中定义的控件 id 查找索引并在此时将其连接起来。

      编辑:好的,根据您构建这些子控件的方式,我会将表单的所有这些内联帮助文本在内部公开为由控件 id 索引的属性,该属性将为您提供帮助文本或空字符串。我不确定我是否得到了 MyCrazyForm.Instance。

      【讨论】:

      • XML 由第三方应用程序提供。不可能在任何合理的时间范围内修改 XML。这就是为什么我希望从 ASPX 端增强它
      • 好的,现在我看到您正在自定义表单中包含这些文本。因此,您应该在自定义表单控件中处理 XML 解析和 HelpText 解析。就像我说的,解析你的文本,然后解析第 3 方 XML 并将它们组合起来。
      • 运行时您好。我明白了,目前正在这样做。我的问题是什么是“赌注”(简单,最干净,最灵活?)将在顶层(在页面中的控件中)解析的数据通过 3 或 4 级控件向下传递到它所在的位置需要。
      【解决方案3】:

      我建议创建一个这样的界面

      interface IHelpTextProvider
      {
          Dictionary<string, string> HelpTexts
          {
              get;
          }
      }
      

      那么你的表单控件就可以实现这个接口,并在创建fieldset和FieldXXX控件的时候传递一个对这个接口的引用。

      或者,您可以按照多语言的建议进行操作,当需要帮助文本时,FieldXXX 控件会递归地通过其父级,直到找到实现 IHelpTextProvider 接口的父级。

      【讨论】:

        【解决方案4】:

        您可以在服务器控件中创建一个事件,只要它想要/需要给定字段的帮助文本,就会引发该事件。表单可以连接事件处理程序并对其进行响应。这样你就不需要传递一些对象来让服务器控制访问信息。为此,我们需要做三件事。

        创建一个 EventArgs 类:

        class HelpTextEventArgs : EventArgs
        {
            public string Text { get; set; }
            public string FieldId { get; private set; }
            public HelpTextEventArgs(string fieldId)
            {
                FieldId = fieldId;
            }
        }
        

        在服务器控件中创建事件:

        public event EventHandler<HelpTextEventArgs> HelpTextRequested;
        
        protected void OnHelpTextRequested(HelpTextEventArgs e)
        {
            EventHandler<HelpTextEventArgs> evt = this.HelpTextRequested;
            if (evt != null)
            {
                evt(this, e);
            }
        }
        // wrapper for the event raising method for easier access in the code
        public string GetHelpText(string fieldId)
        {
            HelpTextEventArgs e = new HelpTextEventArgs(fieldId);
            OnHelpTextRequested(e);
            return e.Text;
        }
        

        ...并以可以访问帮助文本的形式设置事件处理程序:

        private void Page_Load(object sender, EventArgs e)
        {
            ServerControl.HelpTextRequested += ServerControl_HelpTextRequested;
        }
        
        private void ServerControl_HelpTextRequested(object sender, HelpTextEventArgs e)
        {
            e.Text = FindHelpText(e.FieldId);
        }
        

        使用这种方法,即使托管表单不提供帮助文本服务,代码也可以正常工作;服务器控件不依赖于附加事件处理程序这一事实。

        【讨论】:

          【解决方案5】:

          除了查看在控件之间传递信息的不同方式之外,正如此处的其他答案所提出的那样,我认为不同的方法可能是有价值的,具体取决于您的案例的具体情况。与您描述的问题类似的问题 - 将某些特定文本与表单上的某些控件相关联 - 已经解决了更一般的国际化案例,使用 Resources。我知道这与其他答案不同,而不是您在问题中直接提出的问题,但资源似乎很好地满足了需求,如下所述。我没有回答您有关控件之间信息流的具体问题,而是尝试考虑您尝试实现的最终结果。如果我误解了任何事情,请放轻松:-)

          1. 表单中的每个表单和字段都有唯一的标识。因此,可以从表单和字段中唯一地构造资源 ID。
          2. 资源源文件只是 XML,与 UI 的细节完全分离,可以交给非开发人员填写相关的帮助文本。如果你改变 UI,这个文件根本不需要改变。
          3. 在呈现时,您可以使用其资源 ID 获取表单中某个字段的资源,并以任何您想要的方式将文本合并到 UI 中。
          4. 由于 I18N/L10N 使用了相同的方法,因此它有据可查、易于理解、声明性、简单且高效。

          【讨论】:

            【解决方案6】:

            一开始可能比较复杂,但维护起来更容易,为什么不通过 xsl 处理器运行 xml 文件呢? xslt 文件会将您的 helptexts 文件的 helptext 节点分配给相应的字段节点。

             <?xml version="1.0" encoding="ISO-8859-1"?>
            <form>
                <segment>
                    <label>The header</label>
                    <fields>
                        <field>
                            <id>field_name</id>
                            <type>string</type>
                            <label>Name</label>
                            <required>1</required>
                        </field>
                        <field>
                            <id>field_Dob</id>
                            <type>Date</type>
                            <label>Date of Birth</label>
                            <required>1</required>
                        </field>
                    </fields>
                </segment>
            </form>
            

            XSLT 文件:

            <?xml version="1.0" encoding="ISO-8859-1"?>
            <!-- Edited by XMLSpy® -->
            <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
            <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
            
              <xsl:template match="/form/segment/fields/field[id='field_name']">
                <xsl:copy>
                  <xsl:element name="helptext">This is a Name helptext.</xsl:element> 
                  <xsl:apply-templates/>
                </xsl:copy>
              </xsl:template>
            
              <xsl:template match="/form/segment/fields/field[id='field_Dob']">
                <xsl:copy>
                  <xsl:element name="helptext">This is a Date of birth helptext.</xsl:element> 
                  <xsl:apply-templates/>
                </xsl:copy>
              </xsl:template>
            
                <xsl:template match="node() | text()">
                    <xsl:copy>
                        <xsl:copy-of select="@*"/>
                        <xsl:apply-templates/>
                    </xsl:copy>
                </xsl:template>
            
            </xsl:stylesheet>
            

            产生这个:

            <form>
                <segment>
                    <label>The header</label>
                    <fields>
                        <field>
            <helptext>This is a Name helptext.</helptext>
                            <id>field_name</id>
                            <type>string</type>
                            <label>Name</label>
                            <required>1</required>
                        </field>
                        <field>
            <helptext>This is a Date of birth helptext.</helptext>
                            <id>field_Dob</id>
                            <type>Date</type>
                            <label>Date of Birth</label>
                            <required>1</required>
                        </field>
                    </fields>
                </segment>
            </form>
            

            现在可以像以前一样解析这个 xml 文件,但是现在您可以在生成表单元素的同时获取帮助文本。然后您的 HTML 猴子只需要编辑 XSLT 文件,或者您只需包含另一个文件:

              <xsl:template match="/form/segment/fields/field[id='field_Dob']">
                <xsl:copy>
                  <xsl:element name="helptext">
                    <xsl:copy-of select="document('field_Dob.txt')"/> 
                  </xsl:element> 
                  <xsl:apply-templates/>
                </xsl:copy>
              </xsl:template>
            

            您可以在线试用 XSL here

            【讨论】:

            • 谢谢欧赞。您的解决方案对我来说似乎是最干净的。它使我能够保持一切“原样”,并将帮助文本注入到我的主要 XML 文档中。干得好!
            【解决方案7】:

            正如 Ozam 所建议的,您可以使用 XSL。

            具有与第 3 方 xml 文件结构相似的单独 XML 文件,每个 XML 节点都包含 helpText,您可能需要以某种方式合并(?)它们。

            我不知道这是否有任何帮助。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2012-04-06
              • 1970-01-01
              • 1970-01-01
              • 2021-06-13
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多