Desenvolvimento - C#
Utilizando Checkbox em uma TreeView
De uma forma simples e estruturada, vamos ver como preencher e excluir dados de uma TreeView utilizando checkbox para seleção dos Nodes. Neste artigo, devemos também nos atentar a classe DBHelper.
por Alexandre MinatoDepois 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
Criei uma tabela de
segmentos que utiliza uma recursividade (ParentID) para preechimento e o
grande problema era excluir os dados no TreeView. |
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" /> |
|
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.
Anexando
a classe no dbml (LinqToSql) |
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.