Domanda

Ho sviluppato un controllo personalizzato che estende ListBox.L'idea è che il controllo "ricordi" le modifiche ai suoi elementi avvenute sul lato client, ad es.come risultato di una richiesta AJAX.

Il modo in cui funziona è che il controllo esegue anche il rendering di un input nascosto e il risultato della richiesta AJAX viene archiviato nell'input nascosto.Questo viene pubblicato e il metodo LoadPostData() del controllo cerca l'input nascosto e, se l'input nascosto contiene dati, crea la raccolta ListItem da esso.

Funziona perfettamente purché l'utente abbia effettuato una selezione dalla casella di riepilogo.In caso contrario, il metodo LoadPostData() non viene chiamato e di conseguenza la nuova raccolta ListItem non viene creata.(L'ho stabilito utilizzando il debugger.)

Presumo che il metodo LoadPostData venga chiamato solo se la raccolta dati POST include dati corrispondenti all'ID univoco del controllo (ad es.attributo 'nome' in HTML).Se l'utente non ha effettuato una selezione dalla casella di riepilogo, nei dati del post non verrà incluso nulla per l'ID univoco della casella di riepilogo e LoadPostData() non verrà chiamato.È corretto?

Qualcuno può suggerire come posso garantire che il metodo LoadPostData() del mio ListBox personalizzato venga chiamato ogni postback indipendentemente dal fatto che l'utente abbia effettuato una selezione?

Grazie in anticipo, sono davvero bloccato con questo.

Davide

È stato utile?

Soluzione 3

Ho stabilito che il metodo LoadPostData() non viene chiamato a meno che i dati del post non contengano un elemento con lo stesso nome dell'ID univoco del controllo.[Modificare:chiamare Page.RegisterRequiresPostback durante Init() risolve questo problema.] Posso capire perché, ma è piuttosto limitante.

Ho superato il problema non gestendolo affatto durante il metodo LoadPostData().Invece, l'ho gestito in un metodo che chiamo invece in OnLoad().

Quando si utilizza questo approccio è necessario tenere presente due cose:

1) Non hai più accesso all'oggetto postCollection NameValueCollection che viene passato al metodo LoadPostData() come argomento.Ciò significa che devi estrarre i dati del post dalla raccolta Request.Form, il che è un lavoro leggermente più difficile.2) Poiché OnLoad() si verifica dopo il codice di elaborazione ViewState, sarà necessario impostare manualmente SelectedValue dopo aver creato ListItems.In caso contrario, se la casella di riepilogo viene popolata tramite AJAX e l'utente effettua una selezione, la selezione andrà persa.

Spero che questo aiuti qualcuno in futuro.

Altri suggerimenti

Sono un po' in ritardo nell'iniziarmi a farlo ma, solo per riferimento futuro, ecco come ho realizzato qualcosa di simile...

Il mio controllo è un albero che utilizza modelli per i nodi.Il problema con cui avevo a che fare era come acquisire le modifiche lato client allo stato espanso/compresso dei nodi.Ciò che ha funzionato è stato:

In CreateChildControls aggiungi il campo nascosto alla raccolta di controlli del mio controllo root.

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

Nella chiamata OnInit

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

In LoadPostData cerca un valore nella raccolta di post che corrisponda all'UniqueID (non al ClientID) del campo nascosto:

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

All'interno delle classi per i singoli nodi ho del codice che popola gli eventi onclick dei miei pulsanti di attivazione/disattivazione con una chiamata a una funzione JavaScript che accetta come argomenti l'ID del controllo di base e i singoli nodi.

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

Ciò fa sì che trovare il campo nascosto sia abbastanza semplice tramite getElementById:

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

Il JavaScript modifica quindi il valore del campo nascosto come necessario per l'evento che si è verificato.Quando torniamo al server, sono in grado di analizzare il contenuto di questo campo e modificare lo stato del controllo secondo necessità prima che venga nuovamente visualizzato.(Nota:In realtà utilizzo 3 campi nascosti per tenere traccia di eventi diversi ma il concetto è lo stesso)

Spero che questo aiuti gli altri in futuro…

Sembra davvero strano che funzioni solo quando è selezionato un elemento.Un modo rapido per verificare se LoadPostData viene richiamato consiste nell'abilitare la traccia e inserire quanto segue in IPostBackDataHandler.LoadPostData(...).

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

Se questo è il caso, dovresti assicurarti di avere quanto segue:

Page.RegisterRequiresPostBack(this) in OnInit

Ecco un esempio di controllo completo.

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));
        }

    }
}

e la pagina appare così.

<%@ 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>

Quando fai clic su Vai, dovresti vedere "LoadPostData" nella traccia.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top