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

2

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

Сторонняя система предоставляет мне определения 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-код в Control Server и программно генерирую дерево элементов управления. Метки элементов управления передаются в XML.

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

В идеале я бы хотел передать эти справочные тексты из разметки верхнего уровня, чтобы не-разработчики (HTML monkies) могли изменять тексты справки и связывать их с полем с помощью 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 = дата, текст, combobox и т.д.) в зависимости от типа данных.

Типы FieldXXX создают div, а затем несколько стандартных элементов управления .net(TextBox, DropDownList и т.д.), чтобы фактически отобразить себя. Именно в этот момент внутри содержащего div мне нужно вывести текст справки.

Мой вопрос

Что такое "лучший" способ получить эти тексты от элемента управления верхнего уровня до этих дочерних элементов управления, которые на 3 или 4 уровня глубже в дереве управления.

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

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

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

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

Спасибо

Теги:
.net-3.5
servercontrols

7 ответов

1
Лучший ответ

Вначале это может быть сложнее, но упрощает его поддержку, почему бы не запустить XML файл с помощью xsl-процессора? Файл xslt присваивал бы helptext-узлам вашего файла helptexts соответствующим узлам поля.

 <?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 онлайн здесь

  • 0
    Спасибо Озан. Ваше решение кажется мне самым чистым. Это позволяет мне сохранять все как есть и вставлять текст справки в мой основной документ XML. хорошая работа!
1

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

  • Каждая форма и поле в форме имеют уникальный идентификатор. Следовательно, идентификатор ресурса может быть построен однозначно из формы и поля.
  • Файл источника ресурсов - это просто XML, полностью отделенный от специфики пользовательского интерфейса и может быть передан не разработчикам, чтобы заполнить соответствующий текст справки. Если вы измените пользовательский интерфейс, этот файл не должен вообще меняться.
  • При времени рендеринга вы можете просто получить ресурс для поля в форме, используя свой идентификатор ресурса, и включить текст в пользовательском интерфейсе любым, как вы хотите.
  • Поскольку такой же подход используется для I18N/L10N, он хорошо документирован, хорошо понят, декларативен, прост и эффективен.
0

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

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

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

0

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

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

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

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

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

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

0

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

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

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

GetHelpTextFromParent(Control controlParent, string id)

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

0

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

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

EDIT: Хорошо, в зависимости от того, как вы создаете эти дочерние элементы управления, я бы разоблачил все встроенные helptexts формы внутри, как свойство, проиндексированное идентификатором элемента управления, которое предоставит вам текст справки или пустую строку. Я не уверен, что получаю MyCrazyForm.Instance.

  • 0
    XML предоставляется сторонним приложением. Невозможно изменить XML в течение любого разумного периода времени. Вот почему я хочу расширить его с конца ASPX
  • 0
    Хорошо, теперь я вижу, что вы включаете эти тексты в свою форму. Таким образом, вы должны обрабатывать синтаксический анализ XML и HelpText внутри своего пользовательского элемента управления формы. Как я уже сказал, проанализируйте ваши тексты, затем проанализируйте сторонний XML и объедините их.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню