Правильный шаблон для передачи данных дочерним элементам управления в сервере - PullRequest
2 голосов
/ 10 июля 2009

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

Сторонняя система предоставляет мне определения 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 уровня глубже в дереве элементов управления.

На странице будет только одна из этих форм. Должен ли я сделать форму верхнего уровня как синглтон и получить ее так ...?

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

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

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

Спасибо

Ответы [ 7 ]

1 голос
/ 16 июля 2009

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

1 голос
/ 15 июля 2009

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

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

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

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

Я вообще не знаю, поможет ли это каким-либо образом.

0 голосов
/ 15 июля 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);
}

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

0 голосов
/ 14 июля 2009

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

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

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

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

0 голосов
/ 12 июля 2009

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

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

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

0 голосов
/ 12 июля 2009

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

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

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

GetHelpTextFromParent(Control controlParent, string id)

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...