UserControl RenderControl запрашивает тег формы в (C# .NET)

Я спросил как отрендерить HTML-код UserControl и получил код, работающий для динамически сгенерированного UserControl.

Теперь я пытаюсь использовать LoadControl для загрузки ранее созданного элемента управления и вывода его HTML-кода, но он дает мне следующее:

Элемент управления типа TextBox должен быть помещен в тег формы с runat = server.

На самом деле я не добавляю элемент управления на страницу, я просто пытаюсь получить его HTML-код. Есть идеи?

Вот код, с которым я играю:

TextWriter myTextWriter = new StringWriter();
HtmlTextWriter myWriter = new HtmlTextWriter(myTextWriter);

UserControl myControl = (UserControl)LoadControl("newUserControl.ascx");
myControl.RenderControl(myWriter);

return myTextWriter.ToString();

Этого не происходит, когда я удаляю runat = "server" из элементов управления в UserControl.

Jon Smock 02.12.2008 18:52
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
12
1
32 095
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

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

 <input type = "text" />

Обновлено: если вы пытаетесь сделать что-то AJAXy, возможно, вам нужно что-то вроде этого http://aspadvice.com/blogs/ssmith/archive/2007/10/19/Render-User-Control-as-String-Template.aspx

    public static string RenderView<D>(string path, D dataToBind)
    {
        Page pageHolder = new Page();
        UserControl viewControl = (UserControl) pageHolder.LoadControl(path);
        if (viewControl is IRenderable<D>)
        {
            if (dataToBind != null)
            {
                ((IRenderable<D>) viewControl).PopulateData(dataToBind);
            }
        }
        pageHolder.Controls.Add(viewControl);
        StringWriter output = new StringWriter();
        HttpContext.Current.Server.Execute(pageHolder, output, false);

        return output.ToString();
    }

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

Я подумал о добавлении второго UserControl с тем же представлением, за исключением runat = "server" для каждого элемента управления, но это определенно не DRY и накладывает множество ограничений на такие вещи, как раскрывающиеся списки.

Jon Smock 02.12.2008 18:51

Проблема заключается в отсутствии формы, ваши раскрывающиеся списки не смогут взаимодействовать с сервером, лучше всего обернуть содержимое пользовательского элемента управления с помощью <form runat = "server">

Bob 02.12.2008 18:55

У меня есть <form runat = "server"> вокруг всей моей страницы, но этот элемент управления не видит этого, я думаю. Вы все еще рекомендовали бы это?

Jon Smock 02.12.2008 18:56

На самом деле я просто добавляю этот элемент управления на страницу, но у меня возникают проблемы, когда я пытаюсь использовать RenderControl () Control. Есть ли проблема с тем, как я захватываю текст?

Jon Smock 02.12.2008 18:58

Заключение пользовательского элемента управления в тег формы приводит к ошибке. (На странице может быть только один серверный тег формы.)

Jon Smock 02.12.2008 19:09

Вы можете добавить элемент управления на страницу, отобразить html, а затем удалить элемент управления со страницы.

Или попробуйте это:

Page tmpPage = new TempPage(); // temporary page
Control tmpCtl = tmpPage.LoadControl( "~/UDynamicLogin.ascx" );
//the Form is null that's throws an exception
tmpPage.Form.Controls.Add( tmpCtl );

StringBuilder html = new StringBuilder();
using ( System.IO.StringWriter swr = new System.IO.StringWriter( html ) ) {
    using ( HtmlTextWriter writer = new HtmlTextWriter( swr ) ) {
        tmpPage.RenderControl( writer );
    }
}

Я действительно пытался добавить его на страницу, но позвольте мне попробовать, что вы там делаете.

Jon Smock 02.12.2008 18:59

Это говорит о том, что у меня нет доступа к tmpForm в этом контексте. (Также TempPage должна быть страницей, верно?)

Jon Smock 02.12.2008 19:04

Ой, там должна быть tmpPage.

Jon Smock 02.12.2008 19:05

Это грязное решение, которое я использовал на данный момент (заставьте его работать, тогда исправьте, верно?).

Я уже создал новый класс, который наследует класс UserControl и от которого были унаследованы все остальные созданные мной «UserControls». Я назвал его formPartial (кивок в сторону Rails), и он находится внутри метода общедоступной строки renderMyHTML ():

TextWriter myTextWriter = new StringWriter();
HtmlTextWriter myWriter = new HtmlTextWriter(myTextWriter);

UserControl myDuplicate = new UserControl();
TextBox blankTextBox;

foreach (Control tmpControl in this.Controls)
{
    switch (tmpControl.GetType().ToString())
    {
        case "System.Web.UI.LiteralControl":
            blankLiteral = new LiteralControl();
            blankLiteral.Text = ((LiteralControl)tmpControl).Text;
            myDuplicate.Controls.Add(blankLiteral);
            break;
        case "System.Web.UI.WebControls.TextBox":
            blankTextBox = new TextBox();
            blankTextBox.ID = ((TextBox)tmpControl).ID;
            blankTextBox.Text = ((TextBox)tmpControl).Text;
            myDuplicate.Controls.Add(blankTextBox);
            break;

            // ...other types of controls (ddls, checkboxes, etc.)

    }
}

myDuplicate.RenderControl(myWriter);
return myTextWriter.ToString();

Недостатки с головы до ног:

  1. Вам нужен оператор case с каждым возможный контроль (или контролирует вас ожидать).
  2. Вам нужно передать все важные атрибуты из существующий элемент управления (текстовое поле и т. д.) для новый пустой элемент управления.
  3. Не в полной мере использует Управляет методом RenderControl.

Было бы легко испортить 1 или 2. Надеюсь, это поможет кому-то другому придумать более элегантное решение.

Ответ принят как подходящий

В качестве альтернативы вы можете отключить проверку ServerForm / Event на странице, которая отображает элемент управления в строку.

В следующем примере показано, как это сделать.

public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        string rawHtml = RenderUserControlToString();
    }

    private string RenderUserControlToString()
    {
        UserControl myControl = (UserControl)LoadControl("WebUserControl1.ascx");

        using (TextWriter myTextWriter = new StringWriter())
        using (HtmlTextWriter myWriter = new HtmlTextWriter(myTextWriter))
        {
            myControl.RenderControl(myWriter);

            return myTextWriter.ToString();
        }
    }

    public override void VerifyRenderingInServerForm(Control control)
    { /* Do nothing */ }

    public override bool EnableEventValidation
    {
        get { return false; }
        set { /* Do nothing */}
    }
}

К сожалению, вам нужно переопределить его для всей страницы, но у меня это сработало. Хороший.

Jon Smock 08.12.2008 17:46

Да, это не красиво, но легко. Я думаю, вы могли бы ввести логическую переменную класса и использовать ее для включения и выключения "отключения". Таким образом, вы можете просто временно отключить его во время рендеринга элемента управления, а затем снова включить для остальной части страницы. Стоит попробовать, если он вам нужен.

Tom Jelen 08.12.2008 20:02

У меня была такая же проблема с использованием кода, аналогичного @TcKs, и я не смог заставить ни один из этих примеров работать для меня. Я заставил его работать, используя метод LoadControl для UserControl как таковой:

UserControl uc = new UserControl();
Control c = uc.LoadControl("newUserControl.ascx");
c.RenderControl(myWriter);

Другие вопросы по теме