Controles personalizados do ASP.NET – Compostos
-
09-06-2019 - |
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!
- 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.
- 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.
- 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 ^_^
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#!