Правильный шаблон для передачи данных дочерним элементам управления в серверном элементе управления

Я работаю со сторонней системой для реализации некоторых форм на веб-сайте.

Сторонняя система предоставляет мне 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-монашки) могли изменять тексты справки и связывать их с полем по его идентификатору. Что-то вроде этого

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

Должен ли я передавать ссылку на форму в каждый элемент управления по всему дереву (это кажется беспорядочным)?

Я далеко от цели с моей архитектурой этой формы (хотя на данный момент она работает очень хорошо) и должен ли я рассмотреть другой метод реализации?

Спасибо


person Greg B    schedule 10.07.2009    source источник


Ответы (7)


Поначалу это может быть сложнее, но проще в обслуживании, почему бы не запустить файл xml через процессор xsl? Файл 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 онлайн здесь

person Ozan    schedule 15.07.2009
comment
Спасибо Озан. Ваше решение кажется мне самым чистым. Это позволяет мне оставить все как есть и вставить текст справки в мой основной XML-документ. хорошая работа! - person Greg B; 19.07.2009

Помимо рассмотрения различных способов передачи информации между элементами управления, как было предложено в других ответах, я думаю, что другой подход может иметь значение, в зависимости от специфики вашего случая. Проблема, аналогичная описанной вами, — связывание определенного текста с некоторыми элементами управления в форме — была решена для более общего случая интернационализации с помощью ресурсов. Я знаю, что это отличается от других ответов, а не от того, что вы задали в своем вопросе, но ресурсы, похоже, достаточно хорошо удовлетворяют потребности, как описано ниже. Вместо того, чтобы отвечать на ваш конкретный вопрос о потоке информации между элементами управления, я пытаюсь рассмотреть конечный результат, которого вы пытаетесь достичь. Успокойтесь, если я что-то не так понял :-)

  1. Каждая форма и поле внутри формы имеют уникальный идентификатор. Следовательно, идентификатор ресурса может быть создан уникальным образом из формы и поля.
  2. Исходный файл ресурса представляет собой просто XML, полностью отделенный от специфики пользовательского интерфейса и может быть передан не разработчикам для заполнения соответствующим текстом справки. Если вы измените пользовательский интерфейс, этот файл не нужно будет вообще менять.
  3. Во время рендеринга вы можете просто получить ресурс для поля в форме, используя его идентификатор ресурса, и включить текст в пользовательский интерфейс любым удобным для вас способом.
  4. Поскольку тот же подход используется для I18N/L10N, он хорошо документирован, хорошо понятен, декларативен, прост и эффективен.
person Vinay Sajip    schedule 15.07.2009

Как насчет перемещения вверх по родительским элементам управления, пока вы не найдете элемент управления определенного типа или с определенной переменной-членом, называемой «HelpTexts»?

Это подход динамического программирования, но для определенных инфраструктурных элементов дизайна, пока такие подходы ограничены, а также хорошо прокомментированы, почему был выбран этот подход к проектированию, я считаю его приемлемым.

Это должно было бы использовать API-интерфейсы отражения и обобщенную статическую вспомогательную функцию, такую ​​как

GetHelpTextFromParent(Control controlParent, string id)

Затем это проверит controlParent, чтобы увидеть, есть ли в нем переменная-член HelpTexts, а затем найдет текст справки по идентификатору. В противном случае он будет рекурсивно вызывать GetHelpTextFromParent с родителем controlParent до тех пор, пока не наступит подходящее условие завершения. (Я упоминаю «подходящее условие завершения», потому что, вероятно, неоптимально поддерживать это до тех пор, пока вы не перейдете к окну рабочего стола, вы можете захотеть завершить рекурсию до этого, но это будет проблема тестирования/отладки.)

person polyglot    schedule 12.07.2009

Если вы анализируете этот XML в серверном элементе управления и программно создаете дерево элементов управления, как вы гарантируете, что ребята из HTML синхронизируют эти идентификаторы? Если у них есть доступ к этим XML-файлам, возможно, вы должны позволить им добавлять тексты справки прямо здесь, а не на aspx.

Но чтобы ответить на ваш вопрос, я предполагаю, что вы анализируете xml после того, как разметка aspx была прочитана и построена, чтобы вы могли индексировать эти тексты прямо перед анализом XML. Затем, когда вы фактически строите свое динамическое дерево управления, вы просматриваете свой индекс по идентификатору элемента управления, определенному в исходном xml, и подключаете его в этот момент.

РЕДАКТИРОВАТЬ: Хорошо, в зависимости от того, как вы создаете эти дочерние элементы управления, я бы представил все эти встроенные тексты справки формы внутри как свойство, индексированное идентификатором элемента управления, который даст вам текст справки или пустую строку. Однако я не уверен, что получу MyCrazyForm.Instance.

person user134706    schedule 12.07.2009
comment
XML предоставляется сторонним приложением. Невозможно изменить XML в разумные сроки. Вот почему я хочу увеличить его с конца ASPX. - person Greg B; 13.07.2009
comment
Хорошо, теперь я вижу, что вы включаете эти тексты в свою настраиваемую форму. Таким образом, вы должны обрабатывать синтаксический анализ XML и синтаксический анализ HelpText внутри вашего пользовательского элемента управления формой. Как я уже сказал, проанализируйте свои тексты, затем проанализируйте сторонний XML и объедините их. - person user134706; 13.07.2009
comment
Привет время выполнения. Я это понимаю и сейчас этим занимаюсь. Мой вопрос заключается в том, каковы ставки (простой, самый чистый, самый гибкий?) Способ получения данных, которые анализируются на верхнем уровне (в элементе управления на странице), вниз через 3 или 4 уровня элементов управления туда, где это необходимо. - person Greg B; 14.07.2009

Предлагаю сделать такой интерфейс

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

Затем ваш элемент управления формы может реализовать этот интерфейс и передать ссылку на этот интерфейс при создании наборов полей и элементов управления FieldXXX.

В качестве альтернативы вы можете поступить так, как предложил полиглот, и когда требуется текст справки, элемент управления FieldXXX рекурсивно проходит через своих родителей, пока не будет найден родитель, реализующий интерфейс IHelpTextProvider.

person Juozas Kontvainis    schedule 14.07.2009

Вы можете создать событие в серверном элементе управления, которое будет вызываться всякий раз, когда ему нужен/нужен текст справки для данного поля. Форма может подключить обработчик события и ответить на него. Таким образом, вам не нужно передавать какой-либо объект, чтобы предоставить серверу контрольный доступ к информации. Для этого нам нужно сделать три вещи.

Создайте класс 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);
}

При таком подходе код будет работать нормально, даже если форма хостинга не предоставляет службу текстовой справки; управление сервером не зависит от наличия обработчика событий.

person Fredrik Mörk    schedule 15.07.2009

Как предложил Озам, вы можете использовать XSL.

Отдельный XML-файл со структурой, аналогичной структуре стороннего xml-файла, который содержит helpText для каждого XML-узла, был бы хорош, и вам может потребоваться объединить (?) Их каким-то образом.

Не знаю, поможет ли это вообще.

person shahkalpeshp    schedule 18.07.2009