Пользовательский элемент управления ASP.NET: когда вызывается LoadPostData ()? - PullRequest
7 голосов
/ 09 июля 2010

Я разработал пользовательский элемент управления, расширяющий ListBox.Идея состоит в том, что элемент управления «запоминает» модификации своих элементов, которые произошли на стороне клиента, например, в результате запроса AJAX.

Способ, которым он работает, заключается в том, что элемент управления также создает скрытый ввод, иРезультат запроса AJAX сохраняется в скрытом вводе.Это отправляется обратно, и метод элемента управления LoadPostData () ищет скрытый ввод, и, если скрытый ввод содержит данные, создает из него коллекцию ListItem.

Это прекрасно работает так долготак как пользователь сделал выбор из списка .Если нет, метод LoadPostData () не вызывается, и, следовательно, новая коллекция ListItem не создается.(Я установил это с помощью отладчика.)

Я предполагаю, что метод LoadPostData вызывается только в том случае, если сбор данных POST включает данные, соответствующие уникальному идентификатору элемента управления (то есть атрибуту name в HTML).Если пользователь не сделал выбор из списка, в данные публикации не включается ничего для уникального идентификатора списка, а LoadPostData () не вызывается.Это правильно?

Кто-нибудь может подсказать, как я могу гарантировать, что мой метод LoadPostData () моего собственного ListBox вызывается при каждой обратной передаче независимо от того, сделал ли пользователь выбор?

Заранее спасибо - яЯ действительно застрял с этим.

Дэвид

Ответы [ 3 ]

8 голосов
/ 25 февраля 2011

Я немного опаздываю, но для справки, вот как я добился чего-то подобного ...

Мой элемент управления - это дерево, которое использует шаблоны для узлов. Проблема, с которой я имел дело, заключалась в том, как зафиксировать изменения на стороне клиента в развернутом / свернутом состоянии узлов. В итоге получилось:

В CreateChildControls добавьте скрытое поле в коллекцию элементов управления моего корневого элемента управления.

protected override int CreateChildControls(IEnumerable dataSource, bool dataBinding)
{
    ...
    _cdExpanded = new HiddenField();
    _cdExpanded.ID = "cdExpanded";
    this.Controls.Add(_cdExpanded);
    ...
}

В режиме OnInit

protected override void OnInit(EventArgs e)
{
    ...
    Page.RegisterRequiresPostBack(this);
    ...
}

В LoadPostData найдите значение в коллекции сообщений, которое соответствует уникальному (не ClientID) скрытого поля:

public bool LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection)
{
    ...
    string cdExpanded = postCollection[_cdExpanded.UniqueID];
    ...
}

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

    string ToggleScript
    {
        get
        {
            return "ToggleNode('" + this.ClientID + "', '" + _TreeRoot.ClientID + "');";
        }
    }
    protected override void Render(HtmlTextWriter writer)
    {
        ...
        if (this.HasChildren)
        {
            writer.AddAttribute("onclick", ToggleScript);
        }
        ...
    }

Это позволяет легко найти скрытое поле с помощью getElementById:

function ToggleNode(nodeID, treeID) {
var cdExpanded = document.getElementById(treeID + "_cdExpanded");
...
}

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

Надеюсь, это поможет другим в будущем ...

3 голосов
/ 09 июля 2010

Звучит странно, что работать только тогда, когда выбран элемент.Быстрый способ проверить, вызывается ли LoadPostData, чтобы включить трассировку, и поместить следующее в IPostBackDataHandler.LoadPostData (...).

Page.Trace.Write("My control", "LoadPostData");

Если это так, вы должны убедиться, что вы 'Вы получили следующее:

Page.RegisterRequiresPostBack(this) in OnInit

Вот полный пример элемента управления.

using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel.Design;
using System.ComponentModel;
using System.Web.UI.Design;

namespace Controls
{
    public sealed class ExtendedListBoxDesigner : ControlDesigner
    {

        public override string GetDesignTimeHtml()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("<div>My designer</div>");
            return sb.ToString();
        }

    }

    [DesignerAttribute(typeof(ExtendedListBoxDesigner), typeof(IDesigner))]
    public class ExtendedListBox : ListBox, INamingContainer, IPostBackDataHandler 
    {
        bool IPostBackDataHandler.LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection)
        {
            Page.Trace.Write("ExtendedListBox", "LoadPostData");
            return true;
        }


        protected override void OnInit(EventArgs e)
        {
            Page.RegisterRequiresPostBack(this);
            base.OnInit(e);
        }

        protected override void RenderContents(HtmlTextWriter writer)
        {
            base.RenderContents(writer);
            writer.Write(string.Format("<input type=\"hidden\" name=\"{0}_dummy\" value=\"alwaysPostBack\">", this.ID));
        }

    }
}

и страница выглядит следующим образом.

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="ControlSamlpe._Default" Trace="true" %>
<%@ Register Assembly="Controls" Namespace="Controls" TagPrefix="sample" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <sample:ExtendedListBox runat="server" ID="extListBox"></sample:ExtendedListBox>
    <asp:Button runat="server" ID="go" />
    </div>
    </form>
</body>
</html>

Когда вы нажимаете наидти, вы должны увидеть «LoadPostData» в трассировке.

1 голос
/ 09 июля 2010

Я установил, что метод LoadPostData () не вызывается, если данные публикации не содержат элемент с тем же именем, что и UniqueID элемента управления. [Редактировать: вызов Page.RegisterRequiresPostback во время Init () преодолевает это.] Я понимаю, почему, но это довольно ограничивающее.

Я преодолел проблему, вообще не обрабатывая ее во время метода LoadPostData (). Вместо этого я обработал его в методе, который я вызываю в OnLoad ().

При использовании этого подхода необходимо иметь в виду две вещи:

1) У вас больше нет доступа к объекту postCollection NameValueCollection, который передается методу LoadPostData () в качестве аргумента. Это означает, что вам нужно извлечь данные поста из коллекции Request.Form, что немного сложнее. 2) Поскольку OnLoad () происходит после кода обработки ViewState, вам нужно будет вручную установить SelectedValue после создания ListItems. Если вы этого не сделаете, если список заполнен через AJAX и пользователь сделает выбор, выбор будет потерян.

Я надеюсь, что это поможет кому-то в будущем.

...