none
Registrar controle apenas 1 vez por página RRS feed

  • Pergunta

  • Tenho uma classe de controle que deve fazer uma ação no ato do método "Render(HtmlTextWriter)", mas apenas QUANDO O PRIMERIO CONTROLE DO TIPO FOR CHAMADO. Os seguintes que estejam na mesma página (ou mesmo sub-controles da página, como em repeaters, user controls etc) NÃO DEVEM EXECUTAR A AÇÃO.

    É algo assim:

    public class MyControl : TextBox
    {
        protected void My1TimeAction(HtmlTextWriter writer)
        {
            //Essa é a ação que será executada ...
            //Ela está escrita já e funciona
        }
    
        protected bool IsFirstToRender()
        {
            //Aqui é que eu preciso que, se qualquer outro
            //Controle do tipo "MyControl" (ou derivado) nesta
            //Page já executou, então deve retornar "true"
            return false;
        }
    
        protected override void Render(HtmlTextWriter writer)
        {
            if (this.IsFirstToRender()) { this.My1TimeAction(writer); }
            base.Render(writer);
        }
    }

    É possível? Um exemplo para mostrar o que deve acontecer:

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="default.aspx.cs" Inherits="CWEB.Web.UI.DefaultPage" %>
    <!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 id="main_head" runat="server">
        <meta http-equiv="content-type" content="text/html;charset=utf-8" />
        <title>Central Web</title>
    </head>
    <body id="login_body">
        <form id="main_login" class="main_login" runat="server">
            <uc:MyControl runat="server" ID="cnt1" />
            <uc:MyControl runat="server" ID="cnt2" />
            <uc:MyControl runat="server" ID="cnt3" />
            <uc:MyControl runat="server" ID="cnt4" />
        </form>
    </body>
    </html>

    Neste caso, quando "cnt1" for chamado (no método Render) ele deve executar "My1TimeAction", mas "cnt2", "cnt3" e "cnt4" NÃO PODEM EXECUTAR, porque "cnt1" já terá feito. Note, o que tem em comum é que todos estão na mesma PÁGINA - mesmo que eu tenha um "MyControl" em um UserControl, mesmo assim ele deve ser contado.


    sexta-feira, 26 de fevereiro de 2016 21:32

Respostas

  • Sammuel,

    Acho que a solução pode ser utilizar o ViewState. Ex:

    protected bool IsFirstToRender()
    {
        object elemento = this.ViewState["elemento"];
        return (elemento == null);
    }

    protected override void Render(HtmlTextWriter writer)
    {
        if (this.IsFirstToRender())
        {
            this.My1TimeAction(writer);
            ViewState["elemento"] = "renderizado";
        }
        base.Render(writer);
    }

    Links que podem ser úteis:

    https://msdn.microsoft.com/en-us/library/1whwt1k7.aspx

    https://msdn.microsoft.com/en-us/library/aa478975.aspx

    • Marcado como Resposta SammuelMiranda quinta-feira, 3 de março de 2016 11:50
    quinta-feira, 3 de março de 2016 05:30
  • Cesar, obrigado por responder.

    Isso é mais ou menos o que eu estava testando, mas tem um problema. o "ViewState" acessado por este controle é DELE. Para isso funcionar eu teria que acessar o "ViewState" da página em que o controle está alocado. Porque se eu tiver 2 controles do tipo "MyControl" cada um deles vai executar a ação.

    O objetivo não é impedir que a ação aconteça mais de uma vez (ou seja, só na primeira vez que o controle renderiza); o objetivo é executar apenas 1 vez, por renderização, apenas no primeiro controle.

    Se a página fosse:

    public class MyPage : Page
    {
        protected MyControl controle1;
        protected MyControl controle2;
        protected MyControl controle3;
        protected MyControl controle4;
        protected MyControl controle5;
        protected MyControl controle6;
        protected MyControl controle7;
        protected MyControl controle8;
    }

    A cada vez que fosse renderizada a página (mesmo postback, etc) a função "IsFirstToRender" deveria retornar verdadeiro para o "controle1", e falso para todos os outros ("controle2" ao "controle8"). Entende?

    Editado:

    Acabei de pesquisar um pouco mais e achei um tópico que pode ser a solução. Alguém postou no StackOverflow (why-cant-i-access-page-viewstate-in-usercontrol). Acredito que isso resolve. A variável declarada no HttContext, assim quando o Request terminar ela será destruída. Meu dilema era que eu precisava de uma variável "static" mas que o escopo não fosse o programa e sim o "request". Isso se adequa.

    • Editado SammuelMiranda quinta-feira, 3 de março de 2016 11:49 Possível Solução
    • Marcado como Resposta SammuelMiranda quinta-feira, 3 de março de 2016 11:50
    quinta-feira, 3 de março de 2016 11:40

Todas as Respostas

  • Alguma ideia de como fazer funcionar a "IsFirstToRender()"?
    domingo, 28 de fevereiro de 2016 13:47
  • Estive procurando uma variável (ou um lugar que eu possa criar uma variável) que tenha como escopo até o Response ser completado - não achei nada; imagino que isso resolveria meu problema pois, o que preciso é uma variável estática "Integer" para saber quantos controles já renderizaram (do tipo e derivados) - se fosse um programa Windows Forms.

    Mas como as variáveis estáticas tem como escopo o aplicativo, independente das sessões, páginas etc - preciso que uma variável que seja aplicada aquela Request/Response. Alguma ideia?

    segunda-feira, 29 de fevereiro de 2016 11:17
  • Help please!! rsrs
    quarta-feira, 2 de março de 2016 11:33
  • Sammuel,

    Acho que a solução pode ser utilizar o ViewState. Ex:

    protected bool IsFirstToRender()
    {
        object elemento = this.ViewState["elemento"];
        return (elemento == null);
    }

    protected override void Render(HtmlTextWriter writer)
    {
        if (this.IsFirstToRender())
        {
            this.My1TimeAction(writer);
            ViewState["elemento"] = "renderizado";
        }
        base.Render(writer);
    }

    Links que podem ser úteis:

    https://msdn.microsoft.com/en-us/library/1whwt1k7.aspx

    https://msdn.microsoft.com/en-us/library/aa478975.aspx

    • Marcado como Resposta SammuelMiranda quinta-feira, 3 de março de 2016 11:50
    quinta-feira, 3 de março de 2016 05:30
  • Cesar, obrigado por responder.

    Isso é mais ou menos o que eu estava testando, mas tem um problema. o "ViewState" acessado por este controle é DELE. Para isso funcionar eu teria que acessar o "ViewState" da página em que o controle está alocado. Porque se eu tiver 2 controles do tipo "MyControl" cada um deles vai executar a ação.

    O objetivo não é impedir que a ação aconteça mais de uma vez (ou seja, só na primeira vez que o controle renderiza); o objetivo é executar apenas 1 vez, por renderização, apenas no primeiro controle.

    Se a página fosse:

    public class MyPage : Page
    {
        protected MyControl controle1;
        protected MyControl controle2;
        protected MyControl controle3;
        protected MyControl controle4;
        protected MyControl controle5;
        protected MyControl controle6;
        protected MyControl controle7;
        protected MyControl controle8;
    }

    A cada vez que fosse renderizada a página (mesmo postback, etc) a função "IsFirstToRender" deveria retornar verdadeiro para o "controle1", e falso para todos os outros ("controle2" ao "controle8"). Entende?

    Editado:

    Acabei de pesquisar um pouco mais e achei um tópico que pode ser a solução. Alguém postou no StackOverflow (why-cant-i-access-page-viewstate-in-usercontrol). Acredito que isso resolve. A variável declarada no HttContext, assim quando o Request terminar ela será destruída. Meu dilema era que eu precisava de uma variável "static" mas que o escopo não fosse o programa e sim o "request". Isso se adequa.

    • Editado SammuelMiranda quinta-feira, 3 de março de 2016 11:49 Possível Solução
    • Marcado como Resposta SammuelMiranda quinta-feira, 3 de março de 2016 11:50
    quinta-feira, 3 de março de 2016 11:40