Pergunta

Resumo

Olá a todos,
OK, mais adiante em minhas aventuras com controles personalizados...

Em resumo, aprendi sobre três "classes" principais de controles personalizados.Fique à vontade para me corrigir se alguma coisa estiver errada!

  1. Controles de usuário - Que herda de Controle de usuário e estão contidos em um ASCX arquivo.Eles são bastante limitados no que podem fazer, mas são uma maneira rápida e leve de obter alguma semelhança entre a interface do usuário e o suporte do designer.
  2. Controles compostos personalizados - Estes são controles que herdam de WebControl onde você adiciona controles pré-existentes ao controle dentro do CriarControlesCrianças método.Isso proporciona grande flexibilidade, mas falta suporte de designer sem codificação adicional.Eles são altamente portáteis, pois podem ser compilados em uma DLL.
  3. Controles renderizados personalizados - Semelhante aos controles compostos personalizados, eles são adicionados a um projeto da Biblioteca de controles da Web.A renderização do controle é completamente controlada pelo programador, substituindo o Renderizar método.

Meus pensamentos..

OK, enquanto brincava com composições personalizadas, encontrei o seguinte:

  • Você tem pouco/nenhum controle sobre a saída HTML, dificultando a "depuração".
  • O CriarControlesCrianças (e métodos subsequentes) podem ficar muito ocupados com Controls.Add(meuControl) em todos os lugares.
  • Achei a renderização de tabelas (seja para layout ou conteúdo) consideravelmente estranha.

As questões)..

Então, eu admito, sou novo nisso, então posso estar errado com alguns dos meus pontos mencionados acima.

  • Você usa Compósitos?
  • Você tem algum truque legal para controlar a saída HTML?
  • Você acabou de dizer "para o inferno com isso" e seguir em frente e criar um controle renderizado personalizado?

É algo que estou ansioso para firmar em minha mente, pois sei o quanto bom o desenvolvimento do controle pode reduzir o tempo geral de desenvolvimento.

Aguardo suas respostas ^_^

Foi útil?

Solução

Eu digo, vá em frente com o controle renderizado personalizado.Acho que na maioria dos casos o composto pode ser feito e usado mais facilmente em um UserControl, mas qualquer coisa além disso e você precisaria ter um grau de controle mais refinado (trocadilho não intencional) para merecer sua própria estratégia de renderização.

Talvez existam controles que sejam simples o suficiente para merecer um composto (por exemplo, uma caixa de texto combinada com um selecionador de data baseado em javascript/dhtml, por exemplo), mas além desse exemplo, parece que os controles renderizados personalizados são o caminho a percorrer.

Outras dicas

Aqui está outro método de extensão que uso para renderização personalizada:

 public static void WriteControls
        (this HtmlTextWriter o, string format, params object[] args)
 { 
    const string delimiter = "<2E01A260-BD39-47d0-8C5E-0DF814FDF9DC>";
    var controls  = new Dictionary<string,Control>();

    for(int i =0; i < args.Length; ++i)
    { 
       var c = args[i] as Control; 
       if (c==null) continue;
       var guid = Guid.NewGuid().ToString();
       controls[guid] = c;
       args[i] = delimiter+guid+delimiter;
    }

    var _strings = string.Format(format, args)
                         .Split(new string[]{delimiter},
                                StringSplitOptions.None);
    foreach(var s in _strings)
    { 
       if (controls.ContainsKey(s)) 
           controls[s].RenderControl(o);
       else 
           o.Write(s);
    }
}

Então, para renderizar um composto personalizado no método RenderContents() eu escrevo isto:

protected override void RenderContents(HtmlTextWriter o)
{ 
    o.WriteControls
         (@"<table>
               <tr>
                    <td>{0}</td>
                    <td>{1}</td>
               </tr>
             </table>"
            ,Text
            ,control1);
 }

Rob, você está certo.A abordagem que mencionei é uma espécie de híbrida.A vantagem de ter arquivos ascx por perto é que em todos os projetos que vi, os designers se sentiriam mais confortáveis ​​com a edição da marcação real e com o ascx você e um designer podem trabalhar separadamente.Se você não planeja alterações reais de CSS/marcação/design nos próprios controles posteriormente, você pode optar por um controle renderizado personalizado.Como eu disse, minha abordagem só é relevante para cenários mais complicados (e provavelmente é aí que você precisa de um designer :))

Costumo usar controles compostos.Em vez de substituir Render ou RenderContents, apenas atribua a cada Control uma CssClass e use folhas de estilo.Para vários Controls.Add, eu uso um método de extensão:

//Controls.Add(c1, c2, c3)
static void Add(this ControlCollection coll, params Control[] controls)
 { foreach(Control control in controls) coll.Add(control);
 }

Para uma renderização rápida e suja, eu uso algo assim:

writer.Render(@"<table>
                   <tr><td>{0}</td></tr>
                   <tr>
                       <td>", Text);
control1.RenderControl(writer);
writer.Render("</td></tr></table>");

Para inicializar propriedades de controle, uso a sintaxe do inicializador de propriedades:

childControl = new Control {  ID="Foo"
                            , CssClass="class1"
                            , CausesValidation=true;
                           };

O uso de controles compostos personalizados é útil em uma situação em que você tem um aplicativo da Web grande e deseja reutilizar grandes blocos em muitos lugares.Então você adicionaria apenas controles filhos daqueles que está desenvolvendo, em vez de se repetir.Em um grande projeto em que trabalhei recentemente, o que fizemos foi o seguinte:

  • Todo controle composto possui um contêiner.Usado como embrulho para tudo dentro do controle.
  • Todo controle composto possui um modelo.Um arquivo ascx (sem a diretiva <%Control%>) que contém apenas a marcação do modelo.
  • O contêiner (sendo um controle em si) é inicializado a partir do modelo.
  • O contêiner expõe propriedades de todos os outros controles do modelo.
  • Você só usa this.Controls.Add([the_container]) em seu controle composto.

Na verdade, você precisa de uma classe base que cuide da inicialização de um contêiner com o modelo especificado e também lance exceções quando um controle não for encontrado no modelo.É claro que isso provavelmente será um exagero em um aplicativo pequeno.Se você não reutilizou código e marcação e deseja apenas escrever controles simples, é melhor usar User Controls.

Você pode usar esta técnica para facilitar o tempo de design:

http://aspadvice.com/blogs/ssmith/archive/2007/10/19/Render-User-Control-as-String-Template.aspx

Basicamente, você cria uma instância de um controle de usuário em tempo de execução usando o método LoadControl, depois entrega a ele algum tipo de statebag e, em seguida, anexa-o à árvore de controle.Portanto, seu controle composto funcionaria mais como um controlador, e o arquivo .ascx seria como uma visualização.

Isso pouparia o trabalho de ter que instanciar toda a árvore de controle e estilizar o controle em C#!

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top