将数据传递到服务器控件中的子控件的正确模式

发布于 2024-07-26 04:32:28 字数 1652 浏览 6 评论 0原文

我正在与第三方系统合作在网站中实现某些表单。

第三方系统为我提供了这些表单的 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"];
}

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

我的这个架构(尽管目前运行得非常好)形式是否已经离目标很远了?我应该考虑不同的实现方法吗?

谢谢

I'm working with a 3rd party system to implement some forms in a website.

The 3rd party system provides me with XML definitions for these forms.
e.g.

<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>

I am parsing this XML in a Server Control and programatically generating a tree of controls. The labels of the controls are passed through in the XML.

It is part of our proposal to "inject" little help texts into this form.

Ideally I would like to pass these help texts in from the markup of the top level control so that non-developers (HTML monkies) can change the help texts, and associate them with the field by it's ID. Something like so

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

The controls are parsed recursively.

The Form creates a fieldset for each segment, fieldsets create many FieldXXX (where XXX = date, text, combobox etc) depending on the data type.

The FieldXXX types create a div and then several standard .net controls (TextBox, DropDownList, etc) to actually render themselves. It is at this point, within the containing div that I need to output the help text.

My Question

What is the "best" way to get these texts from the top-level form control to these child controls which are 3 or 4 levels deeper in the control tree.

There will only ever be one of these forms on a page.
Should I make the top level form as Singleton and get it like so...?

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

Should I pass a reference to the form into every control all the way down the tree (this seems messy)?

Am I miles of target with my architecture of this (although it's working realyl nicely at the moment) form and should I look at a different method of implementation?

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

瑾兮 2024-08-02 04:32:28

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

 <?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 此处

It may be more complicated at first, but makes it easier to maintain, why not run the xml file through an xsl procesor? The xslt file would assign the helptext nodes of your helptexts file to the corresponding field nodes.

 <?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 file:

<?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>

yields this:

<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>

This xml file can now be parsed like before, but now you can get the help text at the same time as you are generating the form elements. Your HTML monkies then only need to edit the XSLT file, or you simply include another file :

  <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>

You can try out XSL online here

沙沙粒小 2024-08-02 04:32:28

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

  1. 每个表单和表单中的字段都有一个唯一的标识。 因此,可以根据表单和字段唯一地构造资源ID。
  2. 资源源文件只是 XML,与 UI 的细节完全分离,可以交给非开发人员来填充相关的帮助文本。 如果您更改 UI,则此文件根本不需要更改。
  3. 在渲染时,您可以使用资源 ID 获取表单中字段的资源,并按照您想要的方式将文本合并到 UI 中。
  4. 由于 I18N/L10N 使用相同的方法,因此它有充分的文档记录、易于理解、声明性、简单且高性能。

As well as looking at different ways of passing information between controls, as the other answers here have put forward, I think that a different approach may be of value, depending on the specifics of your case. An analogous problem to the one you describe - associating some specific text with some controls on a form - has been solved for the more general case of internationalization, with Resources. I know this is different from the other answers and not directly what you asked in your question, but Resources seem to meet the needs quite well, as described below. Rather than answer your specific question about information flow between controls, I'm trying to consider the end result you're trying to achieve. Go easy on me if I've misunderstood anything :-)

  1. Each form and field within a form have a unique identity. Hence, a resource ID can be constructed uniquely from the form and field.
  2. A resource source file is just XML, completely separate from the specifics of the UI and can be given over to non-developers to fill up with the relevant help text. If you change the UI, this file need not change at all.
  3. At render time, you can just get the resource for a field in a form using its resource ID and incorporate the text in the UI any how you want.
  4. As the same approach is used for I18N/L10N, it is well documented, well understood, declarative, simple and performant.
装迷糊 2024-08-02 04:32:28

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

这是一种动态编程方法,但对于设计的某些基础设施元素,只要这些方法是有限的,并且对为什么采用这种设计方法进行了很好的评论,我认为它是可以接受的。

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

GetHelpTextFromParent(Control controlParent, string id)

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

What about traversing upwards the parents of the control until you find a control of the certain type, or with a specific member variable called "HelpTexts"?

This is a dynamic programming approach, but for certain infrastructural elements of design, as long as such approaches are limited, as well as being well-commented as to why that design approach was taken, I'd find it acceptable.

This would be to use the reflection APIs, and a generalised static helper function, such as

GetHelpTextFromParent(Control controlParent, string id)

This would then inspect the controlParent to see if it had the member variable HelpTexts within it, and then look up by id the helptext. If not, it would recursively call GetHelpTextFromParent with the parent of controlParent, until a suitable terminating condition. (I mention "suitable terminating condition" because it is probably suboptimal to keep this up until you get to the desktop window, you may want to terminate the recursion prior to then, but this would be a testing/debugging issue.)

临走之时 2024-08-02 04:32:28

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

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

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

If you're parsing this XML in a Server Control and programatically generating a tree of controls how do you make sure the HTML guys keep those IDs in sync? If they have access to those XMLs maybe you should let them add helpTexts right there and not on the aspx.

But to answer your question, I suppose you're parsing the xml after the aspx markup was read and built so you could index those texts right before parsing the XML. Then when you actually build your dynamic control tree you look up your index by the control's id defined in you source xml and hook it up at this point.

EDIT: Okay, depending on how you build those child controls, I'd expose all of those inline helptexts of the form internally as a property indexed by the control id which would give you the help text or an empty string. I'm not sure I get the MyCrazyForm.Instance though.

盗琴音 2024-08-02 04:32:28

我建议创建一个像这样的接口

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

然后您的表单控件可以实现这个接口并在创建字段集和FieldXXX控件时传递对此接口的引用。

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

I suggest to create an interface like this

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

Then your form control can implement this interface and pass a reference to this interface when creating fieldsets and FieldXXX controls.

Alternatively, you can do as polyglot suggested and when help text is needed, FieldXXX control go recursively through its parents until a parent implementing IHelpTextProvider interface is found.

清风夜微凉 2024-08-02 04:32:28

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

创建一个 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);
}

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

You could create an event in the server control that it would be raised whenever it wants/needs a help text for a given field. The form can hook up an event handler and respond to it. That way you don't need to pass around some object to give the server control access to the information. For this we need to do three things.

Create an EventArgs class:

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

Create the event in the server control:

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;
}

...and set up an event handler in the form that can access the help texts:

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);
}

Using this approach the code will work fine even if the hosting form does not provide the help text service; the server control is not depending on the fact that there is an event handler attached.

錯遇了你 2024-08-02 04:32:28

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

一个单独的 XML 文件,其结构与第 3 方 xml 文件的结构类似,其中每个 XML 节点包含 helpText,这将是很好的选择。 你可能需要以某种方式合并(?)它们。

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

As Ozam suggested, you could use XSL.

A separate XML file with the similar structure as that of the 3rd party xml file which contains helpText per XML node would be good & you might need to merge(?) them in some way.

I dont know if this help in any way, at all.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文