Welcome Guest Search | Active Topics | Sign In | Register

TreeView events firing too many times Options
John Wiles
Posted: Friday, August 26, 2011 10:00:01 PM
Rank: Member
Groups: Member

Joined: 9/17/2008
Posts: 13
I have a TreeView and a CallBackPanel in use on the same page. My goal is to have the CBP display details about the selected TreeView item when it is clicked on, but also allow users to reorder and drag-n-drop items in the TreeView to change sort order and parents.

The details views work as expected, however, when I start drag-n-drop operations I start experiencing an issue. If I move Item 1 from Container A to Container B, OnItemMoved fires once. That's great. Problem is that if I move Item 1 from Container B back to Container A, OnItemMoved fires twice (once for the first move and once for the second). Now, if I simply click on an item OnItemMoved fires twice again. If I move another item from one place to another OnItemMoved fires three times, and again if I simply click on an item OnItemMoved fires three times. The number of times the event fires increments up with each successive move--I've tested it up to 8 moves.

The problem only occurs if I try to use the TreeView as a trigger for the CallbackPanel AND use it's OnItemClick/OnItemMoved events. But I need to use both. So I need some assistance in keeping the OnItemMoved from firing too often.

Thanks!

Code: HTML/ASPX
<div id="divMenuTreeView" style="vertical-align:top;width:205px;height:405px;padding:0px;overflow:visible;border:solid 1px #999999;">
                                <eo:TreeView ID="trvMenuItems"
                                    runat="server"
                                    Height="400px" Width="200px" 
                                    ControlSkinID="None"
                                    RaisesServerEvent="true"
                                    SaveStateCrossPages="true"
                                    StateCookieName="ckiTrvMenuItemsTracking2"
                                    AllowDragDrop="true"
                                    AllowDragReordering="true"
                                    OnItemClick="trvMenuItems_OnItemClick"
                                    OnItemMoved="trvMenuItems_OnItemMoved">
                                    <LookNodes>
                                        <eo:TreeNode CollapsedImageUrl="00030301"
                                            DisabledStyle-CssText="background-color:transparent;border-bottom-style:none;border-left-style:none;border-right-style:none;border-top-style:none;color:Gray;padding-bottom:1px;padding-left:1px;padding-right:1px;padding-top:1px;" 
                                            ExpandedImageUrl="00030302" ImageUrl="00030301" ItemID="_Default" 
                                            NormalStyle-CssText="PADDING-RIGHT: 1px; PADDING-LEFT: 1px; PADDING-BOTTOM: 1px; COLOR: black; BORDER-TOP-STYLE: none; PADDING-TOP: 1px; BORDER-RIGHT-STYLE: none; BORDER-LEFT-STYLE: none; BACKGROUND-COLOR: transparent; BORDER-BOTTOM-STYLE: none" 
                                            SelectedStyle-CssText="background-color:#316ac5;border-bottom-color:#999999;border-bottom-style:solid;border-bottom-width:1px;border-left-color:#999999;border-left-style:solid;border-left-width:1px;border-right-color:#999999;border-right-style:solid;border-right-width:1px;border-top-color:#999999;border-top-style:solid;border-top-width:1px;color:White;padding-bottom:0px;padding-left:0px;padding-right:0px;padding-top:0px;">
                                        </eo:TreeNode>
                                    </LookNodes>
                                    <TopGroup Style-CssText="border-bottom-color:#999999;border-bottom-style:solid;border-bottom-width:1px;border-left-color:#999999;border-left-style:solid;border-left-width:1px;border-right-color:#999999;border-right-style:solid;border-right-width:1px;border-top-color:#999999;border-top-style:solid;border-top-width:1px;color:black;cursor:hand;font-family:Tahoma;font-size:8pt;padding-bottom:2px;padding-left:2px;padding-right:2px;padding-top:2px;">
                                        <Bindings>
                                            <eo:DataBinding Property="Text-Html" DataField="strTextHtml"></eo:DataBinding>
                                            <eo:DataBinding Property="Value" DataField="intMenuID"></eo:DataBinding>
                                        </Bindings>
                                    </TopGroup>
                                </eo:TreeView>
                            </div>
                        </td>
                        <td style="width:12px;"></td>
                        <td>
                        <!--<td style="width:459px;">-->
                            <eo:CallbackPanel ID="cbpMenuItem"
                                runat="server"
                                OnExecute="cbpMenuItem_OnExecute"
                                Triggers="{ControlID:trvMenuItems;Parameter:}"
                                Height="150px"
                                Width="457px">
                                <div id="divMenuItem">
                                    Filler.
                                </div>
                            </eo:CallbackPanel>

Code: C#
public partial class MisEditMenu : System.Web.UI.Page
{
    // general variables
    // ---- for holding value of the menu item selected in the tree
    public int intSelectedValue = 0;
    // ---- for holding value of the next available sort order; for when inserting a new menu item
    public int intNextSortOrder = 0;

    // instantiate the SQL connection
    SqlConnection sqlConn = new SqlConnection();

    //TreeView trvMainMenu;
    DataSet sdsMainMenu = new DataSet();
    SqlDataAdapter sdaMainMenu = new SqlDataAdapter();
    SqlCommand scmGetMenuData = new SqlCommand();
    SqlCommand scmUpdateMenuData = new SqlCommand();

    protected void Page_PreLoad(object sender, EventArgs e)
    {
        //HcDevTool.SendDebugEmail("'Page_PreLoad' fired!");
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        // set up the SQL connection
        sqlConn.ConnectionString = ConfigurationManager.ConnectionStrings["intranet"].ConnectionString;
        sqlConn.Open();

        // ---- START BUILDING TREE VIEW
        // code to bind the main menu **TREEVIEW** generation to SQL (the actual menu is bound in HCnet.master)

        // declare the SQL data adapter

        // build the SQL command that the adapter will run to get the data
        scmGetMenuData.Connection = sqlConn;
        scmGetMenuData.CommandType = CommandType.Text;
        scmGetMenuData.CommandText = "SELECT intMenuID, intParentID, intSortOrder, intNewSortOrder, strTextHtml, strNavigateUrl, strTarget FROM tbl_mainmenu ORDER BY intSortOrder";

        // ---- Build the SQL update command that the adapter will use to update the data
        scmUpdateMenuData.Connection = sqlConn;
        scmUpdateMenuData.CommandType = CommandType.Text;
        scmUpdateMenuData.Parameters.Add("@intMenuID", SqlDbType.BigInt, 8, "intMenuID");
        scmUpdateMenuData.Parameters.Add("@strTextHtml", SqlDbType.VarChar, 64, "strTextHtml");
        scmUpdateMenuData.CommandText = "UPDATE [tbl_mainmenu] SET strTextHtml = @strTextHtml WHERE intMenuID = @intMenuID";

        // set the data adapter's commands
        sdaMainMenu.SelectCommand = scmGetMenuData;
        sdaMainMenu.UpdateCommand = scmUpdateMenuData;

        // fill the data set with the menu data
        sdaMainMenu.Fill(sdsMainMenu, "tbl_mainmenu");

        // set the primary key on the dataset's "tbl_mainmenu"
        DataColumn[] thisPkColumn = new DataColumn[1];
        thisPkColumn[0] = sdsMainMenu.Tables["tbl_mainmenu"].Columns["intMenuID"];
        sdsMainMenu.Tables["tbl_mainmenu"].PrimaryKey = thisPkColumn;

        // build a relationship between the parent/child keys
        DataRelation sdrParentChildMenu = sdsMainMenu.Relations.Add(sdsMainMenu.Tables[0].Columns["intMenuID"], sdsMainMenu.Tables[0].Columns["intParentID"]);
        sdrParentChildMenu.Nested = true;

        // bind the main menu dataset to the treeview
        trvMenuItems.DataSource = sdsMainMenu;
        trvMenuItems.DataBind();
        
        // ---- END BUILDING TREE VIEW

        // Get the next available sort order number in case we need to insert a menu
        try
        {
            SqlCommand scmGetNextSort = new SqlCommand("SELECT (MAX(intSortOrder) + 1) AS intNextSort FROM tbl_mainmenu", sqlConn);
            SqlDataReader sdrGetNextSort = scmGetNextSort.ExecuteReader();
            while (sdrGetNextSort.Read())
            {
                intNextSortOrder = Convert.ToInt32(sdrGetNextSort[0]);
                //HcDevTool.SendDebugEmail("Next sort order number:  " + intNextSortOrder);
            }
            sdrGetNextSort.Close();
            sdrGetNextSort.Dispose();
            sdrGetNextSort = null;
            scmGetNextSort.Dispose();
            scmGetNextSort = null;
        }
        catch (Exception ex)
        {
            HcDevTool.SendDebugEmail("Couldn't retrieve next sort order number.", IsPostBack, ex);
        }
    }

    protected void Page_LoadComplete(object sender, EventArgs e)
    {

    }

    protected void trvMenuItems_OnItemClick(object sender, EO.Web.NavigationItemEventArgs e)
    {
        // set the session variable to the selected node so we can carry it between refreshes
        //Session["intTrvMenuItemsSelectedValue"] = e.TreeNode.Value;

        // take the current node value from the tree
        // intSelectedValue = int.Parse(e.TreeNode.Value);
    }

    protected void trvMenuItems_OnItemMoved(object sender, EO.Web.TreeNodeMovedEventArgs e)
    {
        string strDebugMsg = "";
        strDebugMsg = strDebugMsg + "'trvMenuItems_OnItemMoved' fired!" + Environment.NewLine + Environment.NewLine;

        //HcDevTool.SendDebugEmail(strDebugMsg);

        int intOldParentNodeId = GetNodeID(e.Node);
        int intNewParentNodeId = GetNodeID(e.Node.ParentNode);
        if (intNewParentNodeId != intOldParentNodeId)
        {
            // need to update the DB to reflect a change in parent node
            UpdateParentID(intOldParentNodeId, intNewParentNodeId);
        }

        // prevent multiple OnItemMoved events
        //---this.Response.Redirect(this.Request.Url.AbsoluteUri, false); -- this doesn't work
        //---trvMenuItems.DataBind(); -- this doesn't work
    }

    // Retrieve node ID (folderID) from a TreeNode object --- copied directly from EO documentation example
    private int GetNodeID(EO.Web.TreeNode node)
    {
        try
        {
            return int.Parse(node.Value.Split(',')[0]);
        }
        catch(Exception ex)
        {
            return -1;
        }
    }

    private void UpdateParentID(int oldParentNodeId, int newParentNodeId)
    {
        HcDevTool.SendDebugEmail("'UpdateParentID' fired!" + Environment.NewLine + "Old Parent Node ID:  " + oldParentNodeId.ToString() + Environment.NewLine + "New Parent Node ID:  " + newParentNodeId.ToString());
    }

    protected void cbpMenuItem_OnExecute(object sender, EO.Web.CallbackEventArgs e)
    {
        //HcDevTool.SendDebugEmail("'cbpMenuItem_OnExecute' fired." + System.Environment.NewLine + "Data:  " + e.Data);
    }
}
eo_support
Posted: Monday, August 29, 2011 10:56:27 AM
Rank: Administration
Groups: Administration

Joined: 5/27/2007
Posts: 24,194
Hi,

This is a very interesting combination. The short answer is the TreeView is actually working as expected. : )

1. When you move item from A to B, then back to A, ItemMoved fired twice. That's normal. TreeView fires ItemMoved every time you move an item. It does not try to "combine" them into a single move event. So if you moved one item twice, then ItemMoved will be fired twice. Note that the actual event firing is delayed until the page post back (in your case when ItemClick event is fired). It is NOT fired immediately after you move it;

2. Because all ItemMoved events are delay fired, they are maintained in a list on the client side and then posted back to the server together. For a normal full page post back, this list is cleared after the page reload. Thus they will not accumulate forever. However in your case, they will because the TreeView never had a chance to reload;

To avoid problem 2, you must allow the TreeView to reload after you raises a server event. This usually means to place the TreeView inside the CallbackPanel. That way the TreeView will be reloaded after the callback thus clearing the ItemMoved list.

Hope this helps. Please feel free to let us know if you have any more questions.

Thanks!
John Wiles
Posted: Monday, August 29, 2011 11:39:00 AM
Rank: Member
Groups: Member

Joined: 9/17/2008
Posts: 13
Thanks for the excellent help. I love your products and getting that inside info on how they work is great. Moving the TreeView inside the CallBackPanel did indeed fix the issue, but it introduced another one: now when the CBP reloads, the tree reloads (which is good) and all the branches are collapsed. Is there a way to configure it so the branches remain expanded after the reload?
eo_support
Posted: Monday, August 29, 2011 1:27:53 PM
Rank: Administration
Groups: Administration

Joined: 5/27/2007
Posts: 24,194
Hi,

I believe it should keep it's state automatically unless you did something (such as rebind the TreeView). You may want to try it in a separate page and see if it works as expected. If it still does not work, please post a test page and we will be happy to take a look.

Thanks!
John Wiles
Posted: Monday, August 29, 2011 2:08:49 PM
Rank: Member
Groups: Member

Joined: 9/17/2008
Posts: 13
Thanks! Going from
Code: C#
Treeview.DataBind()


to

Code: C#
if(!IsPostback)
{
Treeview.DataBind()
}


made all the difference!


You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.