Apaixonado por tecnologia. Trabalho com tecnologia desde 2003.

Saiba mais sobre minha vida profissional aqui .

Fale comigo.
Siga-me no Twitter
Ultimos comentários
Calendário de Posts
<<  novembro 2017  >>
stqqssd
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910

Siga o @DicaDoNerd no Twitter e acompanhe as novidades


Depois de apanhar um pouco com o evento SelectedNodeChanged do TreeView do ASP.NET descobri que o fato de você clicar no checkbox não dispara o evendo para o servidor. Procurei um pouco e encontrei este site que funcionou perfeitamente.

Publiquei este artigo que demostra como preencher um TreeView de forma recursiva utilizando LinqToSql, como este não é o foco, não vou entrar em detalhes sobre o preenchimento.

Primeiro vamos montrar a estrutura para exclusão, neste artigo é possível entender as propriedades ObjectTrackingEnabled e DeferredLoadingEnabled. Para a estrutura do Context utilizei uma técnica bem interessante deste livro (que aliás é excelente) que foi originado deste site

image Criei uma tabela de segmentos que utiliza uma recursividade (ParentID) para preechimento e o grande problema era excluir os dados no TreeView.

Criei uma solução bastante simples para este problema. Habilitei o Checkbox no TreeView e passo uma lista de Ids que serão excluídas.

O primeiro passo é habilitar o TreeView e criar um botão para excluir os itens selecionados.

 
 
 
 
 
 
<asp:LinkButton ID="lk" runat="server" OnClick="Excluir" Text="Excluir" />
<asp:TreeView ID="tv" ShowCheckBoxes="All" runat="server" />

image
HTML Resultado.

 

Agora vamos incluir o javascript no projeto que será resposável para selecionar os checkboxs.

<script type="text/javascript">
function OnCheckBoxCheckChanged(evt) {
var src = window.event != window.undefined ? window.event.srcElement : evt.target;
var isChkBoxClick = (src.tagName.toLowerCase() == "input" && src.type == "checkbox");
if (isChkBoxClick) {
var parentTable = GetParentByTagName("table", src);
var nxtSibling = parentTable.nextSibling;
if (nxtSibling && nxtSibling.nodeType == 1)//check if nxt sibling is not null & is an element node
{
if (nxtSibling.tagName.toLowerCase() == "div") //if node has children
{
//check or uncheck children at all levels
CheckUncheckChildren(parentTable.nextSibling, src.checked);
}
}
//check or uncheck parents at all levels
CheckUncheckParents(src, src.checked);
}
}
function CheckUncheckChildren(childContainer, check) {
var childChkBoxes = childContainer.getElementsByTagName("input");
var childChkBoxCount = childChkBoxes.length;
for (var i = 0; i < childChkBoxCount; i++) {
childChkBoxes[i].checked = check;
}
}
function CheckUncheckParents(srcChild, check) {
var parentDiv = GetParentByTagName("div", srcChild);
var parentNodeTable = parentDiv.previousSibling;

if (parentNodeTable) {
var checkUncheckSwitch;

if (check) //checkbox checked
{
var isAllSiblingsChecked = AreAllSiblingsChecked(srcChild);
if (isAllSiblingsChecked)
checkUncheckSwitch = true;
else
return; //do not need to check parent if any(one or more) child not checked
}
else //checkbox unchecked
{
checkUncheckSwitch = false;
}

var inpElemsInParentTable = parentNodeTable.getElementsByTagName("input");
if (inpElemsInParentTable.length > 0) {
var parentNodeChkBox = inpElemsInParentTable[0];
parentNodeChkBox.checked = checkUncheckSwitch;
//do the same recursively
CheckUncheckParents(parentNodeChkBox, checkUncheckSwitch);
}
}
}
function AreAllSiblingsChecked(chkBox) {
var parentDiv = GetParentByTagName("div", chkBox);
var childCount = parentDiv.childNodes.length;
for (var i = 0; i < childCount; i++) {
if (parentDiv.childNodes[i].nodeType == 1) //check if the child node is an element node
{
if (parentDiv.childNodes[i].tagName.toLowerCase() == "table") {
var prevChkBox = parentDiv.childNodes[i].getElementsByTagName("input")[0];
//if any of sibling nodes are not checked, return false
if (!prevChkBox.checked) {
return false;
}
}
}
}
return true;
}
//utility function to get the container of an element by tagname
function GetParentByTagName(parentTagName, childElementObj) {
var parent = childElementObj.parentNode;
while (parent.tagName.toLowerCase() != parentTagName.toLowerCase()) {
parent = parent.parentNode;
}
return parent;
}

</script>

Pronto! Camada de apresentação pronta, vamos preparar a estruta que será responsável pela exclusão.

 

image Anexando a classe no dbml (LinqToSql)

Tem um artigo que demonstra como criar o objeto relacional com o Linq.

 

Crie uma classe DBHelper.

public static class DbHelper
{
public static dbDadosDataContext getContextData(bool ObjectTrackingEnabled)
{
var db = getContextData();
db.ObjectTrackingEnabled = ObjectTrackingEnabled;
return db;
}

public static dbDadosDataContext getContextData(bool ObjectTrackingEnabled, bool DeferredLoadingEnabled)
{
var db = getContextData();
db.ObjectTrackingEnabled = ObjectTrackingEnabled;
db.DeferredLoadingEnabled = DeferredLoadingEnabled;
return db;

}

public static dbDadosDataContext getContextData()
{
//Colocar a connectionString no web.Config
string strCnn = ConfigurationManager.ConnectionStrings["cnnConnectionString"].ConnectionString;
var db = new dbDadosDataContext(strCnn);
db.DeferredLoadingEnabled = false;
db.ObjectTrackingEnabled = false;
return db;
}

}

Agora vamos criar o método responsável pela exclusão.

 

public class Segmento : IDisposable
{
private dbDadosDataContext db;
public Segmento()
{
db = DbHelper.getContextData();
}

public void ExcluirSegmentos(List<int> listSegments)
{
db.ObjectTrackingEnabled = true; // Habilito o tracking por haver manipulação no BD.
var segs = db.SegmentoEntidades.Where(p => listSegments.Contains(p.IDSegmento));
db.SegmentoEntidades.DeleteAllOnSubmit(segs);
db.SubmitChanges();

}

public void PreencherTreeViewSegmento(TreeView objTreeView, int? IDNoCarregar)
{
//A vantagem de utilizar o IQuarable é que a execução do Banco só será realizada no Bind.
IQueryable<SegmentoEntidade> seg = db.SegmentoEntidades
.Where(p => p.Inativo == false)
.OrderBy(p => p.ParentID)
.OrderBy(p => p.Segmento);

//Limpo os nodes existentes.
objTreeView.Nodes.Clear();

var itens = seg.Where(p => (p.ParentID == null ? 0 : p.ParentID) == (IDNoCarregar == null ? 0 : IDNoCarregar))
.OrderBy(p => p.ParentID)
.OrderBy(p => p.Segmento);

//passo por todos os nodes que foi passado como parâmetro para carregar. (organizando em ordem alfabética
foreach (var item in itens)
{
//Preencho o nó pai
TreeNode nodePai = new TreeNode();
nodePai.Value = item.IDSegmento.ToString();
nodePai.Text = item.Segmento;
nodePai.ImageToolTip = item.Segmento;
//nodePai.ImageUrl = _db.IconeEntidades.Where(p => p.IDIcone == item.IDIcone).FirstOrDefault().urlImagem;
//Preecho os filhos
PreencherNoFilho(nodePai, seg);

//Adiciono o nó que foi preenchido
objTreeView.Nodes.Add(nodePai);
}

}
protected void PreencherNoFilho(TreeNode parentNode, IQueryable<SegmentoEntidade> segmentos)
{
//Passo por todos os elementos filhos do nó pai
var itens = segmentos.Where(p => p.ParentID == int.Parse(parentNode.Value)).OrderBy(p => p.ParentID)
.OrderBy(p => p.Segmento)

foreach (var item in itens)
{

TreeNode noFiltro = new TreeNode();
noFiltro.Value = item.IDSegmento.ToString();
noFiltro.Text = item.Segmento;
noFiltro.SelectAction = TreeNodeSelectAction.SelectExpand; //Expando no nó.
parentNode.ChildNodes.Add(noFiltro); //adiciono na coleção de nós
PreencherNoFilho(noFiltro, segmentos); //Preenchemos os filhos deste Node (recursividade)
}


}

~Segmento()
{
this.Dispose();
}

#region IDisposable Members

public void Dispose()
{
GC.Collet();
GC.SuppressFinalize(this);
}

#endregion
}

Agora vamos criar os métodos na camada de apresentação.

Page_Load.

protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
//Preencho o controle treeview
FillControls(); //
//atribuimos o evento click ao checkbox
tv.Attributes.Add("onclick", "OnCheckBoxCheckChanged(event)");

}

}

O método responsável para

Preencher o controle TreeView.

protected void FillControls()
{

using (Segmento seg = new Segmento())
{
seg.PreencherTreeViewSegmento(tv, null);

}

}

Agora vamos criar o método que irá excluir.

protected void Excluir(object sender, EventArgs e)
{
List<int> lista = new List<int>();
//Preencho a lista com os Nodes selecionados.

foreach (TreeNode item in tv.CheckedNodes)
lista.Add(int.Parse(item.Value));

using (Negocio.Cliente.Segmento seg = new Negocio.Cliente.Segmento())
{
seg.ExcluirSegmentos(lista);
}
FillControls();
}

Pronto, de uma forma bem simples e estruturada preenchemos e excluimos itens com checkbox.

Espero que tenham gostado.

Sigam o @DicaDoNerd no Twitter.

          Surgiu a necessidade em um projeto de criar uma estrutura para criar filtrar entidades dinâmicamente com C#. A idéia era criar uma estrutura onde qualquer desenvolvedor pudesse utilizar a estrutura em qualquer lugar, desde que, a entidade estivesse preenchida. Passando muitas horas apanhando, cheguei em uma solução bem viável, tanto no quesito performance quanto no quesito usabilidade. Neste site encontrei bastante informações úteis.

          Hoje, com a evolução do Linq e Expressões lambdas o trabalho no desenvolver reduziu drasticamente. Para filtrar dados em entidade com Linq e Expressão lambdas poderíamos fazer assim:

   1: IList Resultado  = clientes.Where(p => p.Idade > 5).ToList();

           Aí surgiu o desafio, como criar o “Where” e as Expressões dinamicamente:

          Com uma estrutura bem simples, com dois métodos de extensão (um sobrecarregado), onde o usuário pode passar qual a propriedade deseja filtrar, o Tipo de Comparação e o valor que deseja procurar, com isso, Criei também uma classe que pode ser utilizada para executar diversos filtros.

          Como os estrutura utilizada para filtrar (Lst<Filtroentidade>) ficam em um ViewState, pois, há varios controles que implementam a mesma interface, surgiu um problema quando o filtro deveria ser excluído, como não existia um ID (pois os filtros ainda não estavam na base de dados) para cada nova instancia do objeto guardo o hash do objeto para poder excluir. Sempre que um filtro é aplicado, marco a aplicação através da propriedade FiltroAplicado. Assim, as informações não serão filtradas novamente.

Classe que contem a estrutura que utilizada para filtrar a entidade.

   1: public class FiltroEntidade
   2:    {
   3:        public enum TipoComparacao
   4:        {
   5:            Igual,
   6:            Diferente,
   7:            Contem,
   8:            MaiorIgual,
   9:            MenorIgual,
  10:            Maior
  11:  
  12:        }
  13:  
  14:        public int hashCode
  15:        {
  16:            //Atribui o hash de cada item gerado para caso eu precise remover um determinado item de uma lista de filtros.
  17:            get { return this.GetHashCode(); }
  18:        }
  19:  
  20:        public string NomePropriedade { get; set; }
  21:        public TipoComparacao tipoCompracao { get; set; }
  22:        public string ValorProcurar { get; set; }
  23:        public Type Entidade { get; set; }
  24:        public bool FiltroAplicado { get; set; }
  25:  
  26:  
  27:  
  28:    }

Classe que contém os métodos reponsáveis por filtrar os dados da entidade.

   1: public static class Filtro
   2:     {
   3:         /// <summary>
   4:         /// Aplica uma lista de Filtros em uma entidade.
   5:         /// </summary>
   6:         /// <typeparam name="TEntidade">Instancia da entidade que será filtrada</typeparam>
   7:         /// <param name="entidadeOrigem">entidade que está sendo filtrada</param>
   8:         /// <param name="filtros">Lista de Filtros que deverão ser aplicadas</param>
   9:         /// <returns>Retorna um objeto com a lista das entidades filtradas</returns>
  10:         public static IQueryable<TEntidade> Filtrar<TEntidade>(this IQueryable<TEntidade> entidadeOrigem, List<FiltroEntidade> filtros) where TEntidade : class
  11:         {
  12:             //Pega apenas filtros que ainda não foram aplicados, em caso da lista de filtros ser reutilizada
  13:             List<FiltroEntidade> filtrosAplicar = filtros.Where(p => p.FiltroAplicado == false).ToList();
  14:  
  15:             foreach (FiltroEntidade item in filtrosAplicar)
  16:             {
  17:                 entidadeOrigem = entidadeOrigem.Filtrar(item.NomePropriedade, item.tipoCompracao, item.ValorProcurar);
  18:                 item.FiltroAplicado = true;
  19:             }
  20:  
  21:             return entidadeOrigem;
  22:  
  23:         }
  24:  
  25:  
  26:         /// <summary>
  27:         /// Aplica um unico Filtro
  28:         /// </summary>
  29:         /// <typeparam name="TEntidade">Instancia da Entidade</typeparam>
  30:         /// <param name="entidadeOrigem">objeto que será filtrada</param>
  31:         /// <param name="NomePropriedade">Nome da propriedade</param>
  32:         /// <param name="TipoComparacao">Tipo Comparação</param>
  33:         /// <param name="ValorProcurar">Valor que será filtrado filtrar</param>
  34:         /// <returns>Retorna um objeto com a lista das entidades filtradas</returns>
  35:         public static IQueryable<TEntidade> Filtrar<TEntidade>(this IQueryable<TEntidade> entidadeOrigem, string NomePropriedade, Minato.Entidades.FiltroEntidade.TipoComparacao TipoComparacao, string ValorProcurar)
  36:                                                                 where TEntidade : class
  37:         {
  38:  
  39:             Type type = typeof(TEntidade);
  40:             ConstantExpression procurarFiltro = Expression.Constant(ValorProcurar);
  41:             ParameterExpression parametro = Expression.Parameter(type, "p");
  42:             PropertyInfo propriedade = type.GetProperty(NomePropriedade);
  43:             Expression acesssoPropriedade = Expression.MakeMemberAccess(parametro, propriedade);
  44:  
  45:             Type tipo = Nullable.GetUnderlyingType(propriedade.PropertyType);
  46:  
  47:             if (tipo != null)
  48:             {
  49:                 PropertyInfo valProp = typeof(Nullable<>).MakeGenericType(tipo).GetProperty("Value");
  50:                 acesssoPropriedade = Expression.MakeMemberAccess(acesssoPropriedade, valProp);
  51:             }
  52:             else
  53:             {
  54:                 tipo = acesssoPropriedade.Type;
  55:             }
  56:             if (tipo == typeof(Guid))
  57:             {
  58:                 Guid guid = new Guid(ValorProcurar);
  59:                 procurarFiltro = Expression.Constant(guid);
  60:             }
  61:             else
  62:             {
  63:                 procurarFiltro = Expression.Constant(Convert.ChangeType(ValorProcurar, tipo));
  64:             }
  65:  
  66:  
  67:             MethodInfo startsWith = typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) });
  68:             MethodInfo endsWith = typeof(string).GetMethod("EndsWith", new Type[] { typeof(string) });
  69:             MethodInfo contains = typeof(string).GetMethod("Contains", new Type[] { typeof(string) });
  70:             Expression operacaoRealizar = null;
  71:             switch (TipoComparacao)
  72:             {
  73:                 default:
  74:                 case FiltroEntidade.TipoComparacao.Igual:
  75:                     operacaoRealizar = Expression.Equal(acesssoPropriedade, procurarFiltro);
  76:                     break;
  77:                 case FiltroEntidade.TipoComparacao.Diferente:
  78:                     operacaoRealizar = Expression.NotEqual(acesssoPropriedade, procurarFiltro);
  79:                     break;
  80:  
  81:                 case FiltroEntidade.TipoComparacao.Maior:
  82:                     operacaoRealizar = Expression.GreaterThan(acesssoPropriedade, procurarFiltro);
  83:                     break;
  84:                 case FiltroEntidade.TipoComparacao.MaiorIgual:
  85:                     operacaoRealizar = Expression.GreaterThanOrEqual(acesssoPropriedade, procurarFiltro);
  86:                     break;
  87:  
  88:                 case FiltroEntidade.TipoComparacao.Contem:
  89:                     operacaoRealizar = Expression.Call(acesssoPropriedade, contains, procurarFiltro);
  90:                     break;
  91:  
  92:             }
  93:             var ExpressaoWhere = Expression.Lambda(operacaoRealizar, parametro);
  94:             var ResultadoDaExpressao = Expression.Call(typeof(Queryable), "Where", new Type[] { entidadeOrigem.ElementType }, entidadeOrigem.Expression, ExpressaoWhere);
  95:  
  96:             return entidadeOrigem.Provider.CreateQuery<TEntidade>(ResultadoDaExpressao);
  97:         }
  98:     }

Resultado:

Where

 

 

Para quem estiver preocupado com performance, segue aí o comparativo.

Comparativo

É isso mesmo, foi mais performático do que o modelo tradicional de lambda. (Executei 10 vezes, com dois itens na lista, um com tipo de comparação contains e outro com “maior igual“.

Quer saber como foi realizado o comparativo? Pois, em tecnologia a primeira pergunta é: Mas como foi feita esta comparação?

   1: class Program
   2:     {
   3:         static void Main(string[] args)
   4:         {
   5:             List<ClienteEntidade> clientes = new List<ClienteEntidade>();
   6:             Random rnd = new Random();
   7:  
   8:             int QtdadeRegistrosAdicionar = 1000000;
   9:  
  10:             Stopwatch tempo = new Stopwatch();
  11:  
  12:             tempo.Start();
  13:  
  14:             for (int i = 0; i < QtdadeRegistrosAdicionar; i++)
  15:             {
  16:                 clientes.Add(new ClienteEntidade { NomeCliente = "Cliente" + i, Endereco = "Endereço" + i, Idade = i, Salario = rnd.Next(1000, 10000) });
  17:  
  18:             }
  19:             tempo.Stop();
  20:             Console.WriteLine("Tempo gasto para preencher {0} registros: {1}", QtdadeRegistrosAdicionar, tempo.Elapsed);
  21:             List<FiltroEntidade> filtros = new List<FiltroEntidade>();
  22:             filtros.Add(new FiltroEntidade { NomePropriedade = "NomeCliente", tipoCompracao = FiltroEntidade.TipoComparacao.Contem, ValorProcurar = "Cli" });
  23:             filtros.Add(new FiltroEntidade { NomePropriedade = "Idade", tipoCompracao = FiltroEntidade.TipoComparacao.MaiorIgual, ValorProcurar = "300" });
  24:  
  25:             TimeSpan tempoDinamico, TempoTradicional;
  26:             int NumeroVezesExecucao = 10;
  27:             for (int i = 0; i < NumeroVezesExecucao; i++)
  28:             {
  29:                 tempo.Reset();
  30:                 tempo.Start();
  31:                 IList clientesFiltrados = clientes.AsQueryable().Filtrar(filtros).ToList();
  32:                 tempo.Stop();
  33:                 tempoDinamico = tempo.Elapsed;
  34:                 Console.WriteLine("Filtro Dinâmico    {0}", tempo.Elapsed);
  35:                 
  36:                 
  37:                 tempo.Start();
  38:                 IList clientesLambda = clientes.Where(p => p.NomeCliente.Contains("Cli") && p.Idade >= 300).ToList();
  39:                 tempo.Stop();
  40:                 TempoTradicional = tempo.Elapsed;
  41:                 Console.WriteLine("Filtro tradicional {0}", tempo.Elapsed);
  42:  
  43:                 Console.WriteLine("Comparativo (Dinamico - Tradicional): {0}", tempoDinamico - TempoTradicional);
  44:  
  45:  
  46:             }
  47:  
  48:             Console.ReadKey();
  49:         }
  50:     }

 

Espero que tenham gostado.

Baixem a Solução

 
teste