Moderator.. this is for the 'CSS Friendly Control Adapter' forum. I posted this earlier and it was posted to 'Master Pages, Themes and Navigation controls': http://forums.asp.net/thread/1411894.aspx
I have discovered several problems with the treeview adapter.
First, NodeCheckChanged event is refired for every node that is checked in every postback. I created a fix that involves creating a postbackeventreference in the BuildItem method of the TreeViewAdapter.cs file:
if (((item.ShowCheckBox != null) && (item.ShowCheckBox.Value == true)) ||
(treeView.ShowCheckBoxes == TreeNodeTypes.All) ||
((treeView.ShowCheckBoxes == TreeNodeTypes.Leaf) && (!IsExpandable(item))) ||
((treeView.ShowCheckBoxes == TreeNodeTypes.Parent) && (IsExpandable(item))) ||
((treeView.ShowCheckBoxes == TreeNodeTypes.Root) && (item.Depth == 0)))
{
writer.WriteBeginTag("input");
writer.WriteAttribute("type", "checkbox");
writer.WriteAttribute("id", treeView.ClientID + "n" + _checkboxIndex.ToString() + "CheckBox");
writer.WriteAttribute("name", treeView.UniqueID + "n" + _checkboxIndex.ToString() + "CheckBox");
if (item.Checked)
{
writer.WriteAttribute("checked", "checked");
}
// Add event for checkchanged
writer.WriteAttribute("onclick", Page.ClientScript.GetPostBackEventReference(treeView, "c" + (Page.Server.HtmlEncode(item.ValuePath)).Replace("/", "\\"), true));
writer.Write(HtmlTextWriter.SelfClosingTagEnd);
_checkboxIndex++;
} To capture the event, I added the following code to the RaisePostBackEvent:
if (eventArgument != null)
{
if (eventArgument.StartsWith("s") || eventArgument.StartsWith("e"))
{
string selectedNodeValuePath = eventArgument.Substring(1).Replace("\\", "/");
TreeNode selectedNode = treeView.FindNode(selectedNodeValuePath);
if (selectedNode != null)
{
bool bSelectedNodeChanged = selectedNode != treeView.SelectedNode;
selectedNode.Selected = true; // does not raise the SelectedNodeChanged event so we have to do it manually (below).
ExpandToSelectedNode();
if (eventArgument.StartsWith("e"))
{
selectedNode.Expanded = true;
}
if (bSelectedNodeChanged)
{
Extender.RaiseAdaptedEvent("SelectedNodeChanged", new EventArgs());
}
}
}
else if (eventArgument.StartsWith("p"))
{
string parentNodeValuePath = eventArgument.Substring(1).Replace("\\", "/");
TreeNode parentNode = treeView.FindNode(parentNodeValuePath);
if ((parentNode != null) && ((parentNode.ChildNodes == null) || (parentNode.ChildNodes.Count == 0)))
{
ExpandToNode(parentNode);
parentNode.Expanded = true; // Raises the TreeNodePopulate event
}
}
else if (eventArgument.StartsWith("c"))
{
string parentNodeValuePath = eventArgument.Substring(1).Replace("\\", "/");
TreeNode parentNode = treeView.FindNode(parentNodeValuePath);
if (parentNode != null)
{
Extender.RaiseAdaptedEvent("TreeNodeCheckChanged", new TreeNodeEventArgs(parentNode));
}
} I then commented out the the RaiseAdaptedEvent line in the UpdateCheckmarks method:
if (item.Checked != bIsNowChecked)
{
item.Checked = bIsNowChecked;
// Adding postback support for checkmarks
//Extender.RaiseAdaptedEvent("TreeNodeCheckChanged", new TreeNodeEventArgs(item));
}
That line was the cause of the TreeNodeCheckChanged event firing for every checked node.
The second problem I found is the TreeViewAdapter doesn't raise events properly if the treeview is in a webcontrol. This is due to how the RaiseAdapterEvent was created..
public void RaiseAdaptedEvent(string eventName, EventArgs e)
{
string attr = "OnAdapted" + eventName;
if ((AdaptedControl != null) &&
(AdaptedControl.Attributes[attr] != null) &&
(AdaptedControl.Attributes[attr].Length > 0))
{
string delegateName = AdaptedControl.Attributes[attr];
MethodInfo method = AdaptedControl.Page.GetType().GetMethod(delegateName);
if (method != null)
{
object[] args = new object[2];
args[0] = AdaptedControl;
args[1] = e;
method.Invoke(AdaptedControl.Page, args);
}
}
} The Page references cause the code to fail as the method delegate is in a control and not page. I fixed this by changing the code to:
public void RaiseAdaptedEvent(string eventName, EventArgs e)
{
string attr = "OnAdapted" + eventName;
if ((AdaptedControl != null) &&
(AdaptedControl.Attributes[attr] != null) &&
(AdaptedControl.Attributes[attr].Length > 0))
{
string delegateName = AdaptedControl.Attributes[attr];
MethodInfo method = AdaptedControl.Parent.GetType().GetMethod(delegateName);
if (method != null)
{
object[] args = new object[2];
args[0] = AdaptedControl;
args[1] = e;
method.Invoke(AdaptedControl.Parent, args);
}
}
} I did some basic testing and it looks like referencing the parent works a lot better than referencing the page.
The last problem I have figured out yet.. but it is easy to reproduce. I can't get nodes to expand in some of the demos. For example go here:
http://www.asp.net/CSSAdapters/TreeView.aspx
Change the theme to 'Enhanced', then try to expand a node. The nodes won't expand.