Olá pessoal! Enfim, já modelamos o banco de dados e as classes que farão parte do
nosso controle de usuários para sistemas ASP.NET, o exemplo já se encontra na Página
de Suporte, e agora vamos falar sobre as telas de cadastro.
O cadastramento de perfis e usuários será feito de uma maneira que chamo de "single
page module", ou seja, TODO o módulo estará em apenas UMA página. Ela é construída
utilizando panels para controlar a visualização das grades de pesquisa e por janelas
modais que são as telas de cadastro em si.
Esta página, assim como as outras do nosso exemplo, fazem herança visual e de código
(veremos como a parte de herança de código será importante na parte 5) de uma master
page. Portanto, não estranhem a ausência das tags de header, body e form :-)
Quando o módulo de Cadastro de Perfis/Usuários for acessado, é mostrado em primeiro
lugar a grade de pesquisa de Perfis de Usuário. Observem o código desta parte da
página, que mostra as grades dos cadastros, acompanhado de seu code-behind:
<div id="dvSelModulo" style="text-align:center;width:100%">
<span class="textotitulos">Selecione o módulo desejado</span><br />
<asp:DropDownList runat="server" ID="ddlSelecionaModulo" AutoPostBack="true" OnSelectedIndexChanged="ddlSelecionaModulo_SelectedIndexChanged">
<asp:ListItem Text="Cadastro de Perfis de Usuário" Value="1"></asp:ListItem>
<asp:ListItem Text="Cadastro de Usuários" Value="2"></asp:ListItem>
</asp:DropDownList>
</div>
<div id="dvPesqCadPerfil" runat="server">
<asp:UpdatePanel runat="server" ID="UpdPesqCadP">
<ContentTemplate>
<div class="divtitulo">
<span>Cadastro de Perfis de Usuário - Pesquisa</span>
</div>
<div>
<div style="position:absolute;width:250px;">
<span class="textotitulos">Descrição:</span><br />
<asp:TextBox runat="server" ID="tbxPesquisaDescPerfil"></asp:TextBox>
</div>
<div style="width:150px;left:260px;position:relative;top:6px;">
<asp:Button runat="server" ID="btnPesquisarPerfil" Text="Pesquisar Perfil" OnClick="btnPesquisarPerfil_Click" />
</div>
</div><br />
<div style="text-align:center;width:100%;border-top:solid 2px black">
<asp:Button runat="server" ID="btnInserirPerfil" Text="Inserir Novo Perfil" OnClick="btnInserirPerfil_Click" />
</div>
<div>
<asp:GridView runat="server" ID="gvCadPerfil" AutoGenerateColumns="false" OnRowDataBound="gvCadPerfil_RowDataBound" Width="100%">
<HeaderStyle CssClass="gridheader" />
<RowStyle CssClass="gridnormal" />
<Columns>
<asp:BoundField HeaderText="Código" DataField="PerfilId" />
<asp:BoundField HeaderText="Descrição" DataField="Descricao" />
<asp:TemplateField>
<ItemTemplate>
<asp:Button runat="server" ID="btnEditarPerfil" Text="Editar" OnClick="btnEditarPerfil_Click" />
<asp:Button runat="server" ID="btnExcluirPerfil" Text="Excluir" OnClientClick="return confirm('Senta o dedo na bagaça?');"
OnClick="btnExcluirPerfil_Click" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
</ContentTemplate>
</asp:UpdatePanel>
</div>
<div id="dvPesqCadUsu" style="displaynone;" runat="server">
<asp:UpdatePanel runat="server" ID="UpdPesqCadUsu">
<ContentTemplate>
<div class="divtitulo">
<span>Cadastro de Usuários - Pesquisa</span>
</div>
<div>
<div style="position:absolute;width:150px;">
<span class="textotitulos">Nome Completo:</span><br />
<asp:TextBox runat="server" ID="tbxPesqNomeUsu" CssClass="textboxes"></asp:TextBox>
</div>
<div style="width:150px;left:160px;position:absolute;">
<span class="textotitulos">Login:</span><br />
<asp:TextBox runat="server" ID="tbxPesqLoginUsu" CssClass="textboxes"></asp:TextBox>
</div>
<div style="width:150px;position:absolute;left:320px;">
<span class="textotitulos">Perfil:</span><br />
<asp:DropDownList runat="server" ID="ddlPesqPerfilUsu" CssClass="textboxes">
</asp:DropDownList>
</div>
<div style="width:100px;position:absolute;left:480px;">
<span class="textotitulos">Status:</span><br />
<asp:DropDownList runat="server" ID="ddlPesqStatusUsu" CssClass="textboxes">
<asp:ListItem Value="" Text="--TODOS--"></asp:ListItem>
<asp:ListItem Value="A" Text="ATIVO"></asp:ListItem>
<asp:ListItem Value="I" Text="INATIVO"></asp:ListItem>
</asp:DropDownList>
</div>
<div style="position:relative;left:620px;width:100px;top:8px;">
<asp:Button runat="server" ID="btnPesquisarUsu" Text="Pesquisar Usuário" OnClick="btnPesquisarUsu_Click" />
</div>
</div><br />
<div style="width:100%;text-align:center;border-top:solid 2px black;">
<asp:Button runat="server" ID="btnInserirUsuario" Text="Inserir Novo Usuário" OnClick="btnInserirUsuario_Click" />
</div>
<div>
<asp:GridView runat="server" ID="gvPesqUsuarios" AutoGenerateColumns="false" OnRowDataBound="gvPesqUsuarios_RowDataBound" Width="100%">
<HeaderStyle CssClass="gridheader" />
<RowStyle CssClass="gridnormal" />
<Columns>
<asp:BoundField DataField="Login" HeaderText="Login" />
<asp:BoundField DataField="Nome" HeaderText="Nome Completo" />
<asp:BoundField DataField="Status" HeaderText="Status" />
<asp:TemplateField HeaderText="Perfil">
<ItemTemplate>
<asp:Label runat="server" ID="lbPerfil"></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField>
<ItemTemplate>
<asp:Button runat="server" ID="btnEditarUsuario" Text="Editar" OnClick="btnEditarUsuario_Click" />
<asp:Button runat="server" ID="btnExcluirUsuario" Text="Excluir" OnClientClick="return confirm('Senta o dedo na bagaça?');"
OnClick="btnExcluirUsuario_Click" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
</ContentTemplate>
</asp:UpdatePanel>
</div>
Code Behind:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
ViewState.Add("CodigoPerfil", "0");
ViewState.Add("UsuID", "0");
//Populando o combo-box de Pesquisa de Perfil
ddlPesqPerfilUsu.DataSource = TPerfilUsuario.ListarPerfis("");
ddlPesqPerfilUsu.DataValueField = "PerfilId";
ddlPesqPerfilUsu.DataTextField = "Descricao";
ddlPesqPerfilUsu.DataBind();
ddlPesqPerfilUsu.Items.Insert(0, new ListItem("--TODOS--", "0"));
//Populando o combo-box de seleção de perfil do cadastro de usuários
ddlPerfilUsuario.DataSource = TPerfilUsuario.ListarPerfis("");
ddlPerfilUsuario.DataValueField = "PerfilId";
ddlPerfilUsuario.DataTextField = "Descricao";
ddlPerfilUsuario.DataBind();
}
}
protected void ddlSelecionaModulo_SelectedIndexChanged(object sender, EventArgs e)
{
switch ((sender as DropDownList).SelectedIndex)
{
case { dvPesqCadPerfil.Style[HtmlTextWriterStyle.Display] = ""; dvPesqCadUsu.Style[HtmlTextWriterStyle.Display] = "none"; break; }
case { dvPesqCadPerfil.Style[HtmlTextWriterStyle.Display] = "none"; dvPesqCadUsu.Style[HtmlTextWriterStyle.Display] = ""; break; }
}
}
Como vocês podem ver, cada gridview está contido dentro de um div, com o atributo
runat=server. O div correspondente ao grid de perfil se encontra visível, e o de
usuários oculto. Um drop down permite alternar a visibilidade destes divs, conforme
o método SelectedIndexChanged do mesmo: De acordo com a opção, seto o atributo Display
para vazio ou none. E note também que cada div contém seu próprio UpdatePanel.
Cada cadastro tem seus próprios filtros de pesquisa e controles também, de forma
que sejam completamente independentes um do outro.
No evento PageLoad, faço a pré-carga dos combo-boxes do filtro de pesquisa de perfil
e do combo de seleção de perfil do cadastro de usuários, além de inicializar dois
Viewstates que são utilizados para controlar o ID do registro selecionado dos grids.
Vamos detalhar agora o cadastro de Perfil de Usuário, com a sua janela e o code-behind
correspondente:
<div id="dvDetCadPerfil" class="jqmWindow">
<asp:UpdatePanel runat="server" ID="UpdatePanel1">
<ContentTemplate>
<div class="divtitulo">
<span>Cadastro de Perfis de Usuário</span>
</div>
<fieldset>
<span class="textotitulos">Código:</span><br />
<asp:TextBox runat="server" ID="tbxCodigoPerfil" ReadOnly="true" CssClass="textboxes"></asp:TextBox><br />
<span class="textotitulos">Descrição</span><br />
<asp:TextBox runat="server" ID="tbxDescricaoPerfil" CssClass="textboxes"></asp:TextBox><br />
<div>
<asp:Button runat="server" ID="btnCancelarCadPerfil" Text="Cancelar" OnClick="btnCancelarCadPerfil_Click" />
<asp:Button runat="server" ID="btnSalvarPerfil" Text="Salvar" OnClick="btnSalvarPerfil_Click" />
</div>
</fieldset>
<div class="divtitulos">
<span>Módulos que este perfil pode acessar</span>
</div>
<asp:GridView runat="server" ID="gvModulosPerfil" AutoGenerateColumns="false" OnRowDataBound="gvModulosPerfil_RowDataBound" Width="100%">
<HeaderStyle CssClass="gridheader" />
<RowStyle CssClass="gridnormal" />
<Columns>
<asp:BoundField HeaderText="Código do Módulo" DataField="ModuloId" />
<asp:BoundField HeaderText="Descrição do Módulo" DataField="Descricao" />
<asp:TemplateField HeaderText="Tem Acesso?">
<ItemTemplate>
<asp:CheckBox runat="server" ID="chkPermissaoModulo" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</ContentTemplate>
</asp:UpdatePanel>
</div>
protected void gvCadPerfil_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowIndex > -1)
{
(e.Row.FindControl("btnEditarPerfil") as Button).CommandArgument = e.Row.RowIndex.ToString();
(e.Row.FindControl("btnExcluirPerfil") as Button).CommandArgument = e.Row.RowIndex.ToString();
}
}
protected void gvModulosPerfil_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowIndex > -1)
{
(e.Row.FindControl("chkPermissaoModulo") as CheckBox).Checked = (e.Row.DataItem as TPerfilModulo).PodeAcessar.Equals(1);
}
}
private void SalvarDadosPerfil()
{
TPerfilUsuario oTUsrPerfil = new TPerfilUsuario();
bool ok = false;
string script = "";
try
{
oTUsrPerfil.PerfilId = tbxCodigoPerfil.Text.Equals("") ? 0 Int32.Parse(tbxCodigoPerfil.Text);
oTUsrPerfil.Descricao = tbxDescricaoPerfil.Text;
//Atribui os valores selecionados no gridview nos módulosque pode acessar
foreach (GridViewRow r in gvModulosPerfil.Rows)
{
if (r.RowType.Equals(DataControlRowType.DataRow))
{
oTUsrPerfil.Modulos[r.RowIndex].PodeAcessar = (r.FindControl("chkPermissaoModulo") as CheckBox).Checked ? 1 0;
}
}
ok = (ViewState["CodigoPerfil"].ToString().Equals("0") ? oTUsrPerfil.Inserir() oTUsrPerfil.Atualizar());
if (ok)
{
ViewState["CodigoPerfil"] = oTUsrPerfil.PerfilId.ToString();
tbxCodigoPerfil.Text = oTUsrPerfil.PerfilId.ToString();
PesquisarPerfil();
//Populando o combo-box de Pesquisa de Perfil
ddlPesqPerfilUsu.DataSource = TPerfilUsuario.ListarPerfis("");
ddlPesqPerfilUsu.DataValueField = "PerfilId";
ddlPesqPerfilUsu.DataTextField = "Descricao";
ddlPesqPerfilUsu.DataBind();
ddlPesqPerfilUsu.Items.Insert(0, new ListItem("--TODOS--", "0"));
//Populando o combo-box de seleção de perfil do cadastro de usuários
ddlPerfilUsuario.DataSource = TPerfilUsuario.ListarPerfis("");
ddlPerfilUsuario.DataValueField = "PerfilId";
ddlPerfilUsuario.DataTextField = "Descricao";
ddlPerfilUsuario.DataBind();
}
script = Consts.JavaScript.Alert(Consts.Funcoes.Replacer4js(oTUsrPerfil.MsgInfo), false);
}
finally
{
oTUsrPerfil.Dispose();
}
ScriptManager.RegisterStartupScript(this, this.GetType(), "alerta", script, true);
}
private void ExibirDadosPerfil(string pID)
{
TPerfilUsuario oTUsrPerfil = new TPerfilUsuario();
try
{
oTUsrPerfil.PerfilId = Int32.Parse(pID);
oTUsrPerfil.SetByID();
tbxCodigoPerfil.Text = oTUsrPerfil.PerfilId.ToString();
tbxDescricaoPerfil.Text = oTUsrPerfil.Descricao.ToString();
ViewState["CodigoPerfil"] = oTUsrPerfil.PerfilId.ToString();
//Grid de módulos com acesso
gvModulosPerfil.DataSource = oTUsrPerfil.Modulos;
gvModulosPerfil.DataKeyNames = new string[1] { "ModuloID" };
gvModulosPerfil.DataBind();
string script = "$dvModalLoader.jqmHide();$dvDetCadPerfil.jqmShow();";
ScriptManager.RegisterStartupScript(this, this.GetType(), "abre", script, true);
}
finally
{
oTUsrPerfil.Dispose();
}
}
private void PesquisarPerfil()
{
gvCadPerfil.DataSource = TPerfilUsuario.ListarPerfis(tbxPesquisaDescPerfil.Text.ToUpper());
gvCadPerfil.DataKeyNames = new string[1] { "PerfilId" };
gvCadPerfil.DataBind();
}
protected void btnInserirPerfil_Click(object sender, EventArgs e)
{
tbxCodigoPerfil.Text = "";
tbxDescricaoPerfil.Text = "";
ViewState["CodigoPerfil"] = "0";
//Grid de módulos com acesso
TPerfilUsuario pu = new TPerfilUsuario();
try
{
gvModulosPerfil.DataSource = pu.Modulos;
gvModulosPerfil.DataKeyNames = new string[1] { "ModuloID" };
gvModulosPerfil.DataBind();
}
finally
{
pu.Dispose();
}
string script = "$dvModalLoader.jqmHide();$dvDetCadPerfil.jqmShow();";
ScriptManager.RegisterStartupScript(this, this.GetType(), "abre", script, true);
}
protected void btnSalvarPerfil_Click(object sender, EventArgs e)
{
SalvarDadosPerfil();
}
protected void btnCancelarCadPerfil_Click(object sender, EventArgs e)
{
ViewState["CodigoPerfil"] = "0";
string script = "$dvDetCadPerfil.jqmHide();";
ScriptManager.RegisterStartupScript(this, this.GetType(), "abre", script, true);
}
protected void btnPesquisarPerfil_Click(object sender, EventArgs e)
{
PesquisarPerfil();
}
protected void btnEditarPerfil_Click(object sender, EventArgs e)
{
string id = gvCadPerfil.DataKeys[Int32.Parse((sender as Button).CommandArgument)].Value.ToString();
ExibirDadosPerfil(id);
}
protected void btnExcluirPerfil_Click(object sender, EventArgs e)
{
string msg = "";
if (TPerfilUsuario.Excluir(Int32.Parse(gvCadPerfil.DataKeys[Int32.Parse((sender as Button).CommandArgument)].Value.ToString()), out msg))
{
PesquisarPerfil();
}
string script = Consts.JavaScript.Alert(Consts.Funcoes.Replacer4js(msg), false);
ScriptManager.RegisterStartupScript(this, this.GetType(), "alerta", script, true);
}
Como já adiantado, a janela de detalhes do perfil de usuário é uma janela modal
construída pelo plugin jqModal do jQuery (as bibliotecas estão declaradas na master
page e os modais foram inicializados no final da página do módulo); nela estão os
controles que permitem alterar os dados do registro.
Quando clicamos no botão btnInserirPerfil ou btnEditarPerfil, registramos o script
que oculta o modal da requisição AJAX (lembra... no artigo sobre como resolver alguns
pepinos quando misturamos jQuery e ASP.NET Ajax?) e exibe o cadastro. Nestes botões
também colocamos a chave do registro a ser exibido no ViewState "CodigoPerfil".
No botão Inserir, colocamos como chave o valor "0" e colocamos alguns
valores padrão dentro dos textboxes.
Para obtermos o ID do registro que queremos editar a partir do grid de pesquisa,
guardamos esse ID na propriedade CommandArgument dos botões de Editar e Excluir.
Isto pode ser feito no evento OnRowDataBound deste grid, usando um FindControl para
pegarmos o controle desejado, e guardar o DataKey da linha no CommandArgument. Depois,
nos métodos OnClick destes botões, recuperamos este valor.
Note que há nesta janela um gridview que lista os módulos que este perfil pode acessar.
Este gridview é alimentado através da propriedade Modulos da classe TPerfilUsuario.
Esta propriedade é um List de objetos do tipo TPerfilModulo. No evento RowDataBound
deste grid, alteramos a propriedade Checked do checkbox em uma coluna template,
baseando-se na propriedade PodeAcessar do objeto TPerfilModulo da linha que está
sendo "bindada": Se for 1, o checkbox tem o Checked = true.
As diferenças entre o botão de inserir e atualizar são que no primeiro, não inicializamos
valores em um objeto de TPerfilUsuario, ao contrário do segundo, o qual chamamos
o método SetByID baseando-se no valor alimentado no viewstate "CodigoPerfil".
Os métodos de pesquisa e exclusão, não apresentam novidades: Instanciamos a classe
e chamamos os respectivos comandos. Ao ser aplicados, dão um "refresh"
nos dados do grid.
O método SalvarDadosPerfil merece um pouquinho de atenção: Antes de salvarmos o
perfil, varremos o gridview com os módulos através de um laço foreach, e pegamos
o valor do checkbox em cada linha do grid. Este valor é alimentado na propriedade
PodeAcessar da coleção Modulos do perfil que estamos salvando. É como se fosse o
"inverso" do que fazemos no RowDataBound do grid de listagem dos módulos.
Feito isso, damos o comando de Inserir ou Atualizar do perfil. Caso o nosso ViewState
"CodigoPerfil" for zero, insere; caso contrário, atualiza.
Por fim, atualizamos o ViewState com o ID do registro que acabamos de gravar, o
grid da tela inicial e os combo-boxes de seleção de perfil do cadastro de usuários
e damos um alert com o resultado da operação.
O cadastro de Usuários tem funcionamento semelhante ao cadastro de Perfil, dispensando
maiores explicações (são só a classe instanciada e os nomes dos componentes que
mudam hehehe).
Na próxima parte do artigo, faremos a implementação do controle de acesso em um
sistema.
Exemplo
Sistema de Login em ASP.NET (com BD Firebird) (289 kB)
Abraços a todos!
[Update 26/02/2008: Para facilitar o download, ao invés da página
de suporte hospedada no Geocities, estarei movendo os arquivos para hospedagem própria,
diretamente no domínio leonelfraga.com e colocando os links diretos para o arquivo.]