Solved

ToolStripItemClickedEventHandler

Posted on 2011-02-23
22
1,241 Views
Last Modified: 2012-05-11
I am trying to add an event handler to my dropdownitems of my toolstrip. currently when i add the event handler, each time the event is triggered, the dropdownitems are duplicated.

my toolstrip menu items are projects, and each project can have multiple tasks. when a user clicks on the task, the event handler is triggered, which has a method that starts to track time. this also creates a new menu item to stop the timer.

how can i configure my code to prevent the duplicate items?

Cheers,
Brendan
private void SetupMenu()
        {
            ctxMainMenu.Items.Clear();
            
            //ctxMainMenu.Refresh();
            _workItemValid = false;

            ToolStripMenuItem newMenu = null;

            if (_currentWorkItemID > 0)
            {
                newMenu = new ToolStripMenuItem("Stop Working On WorkItem:" + _currentWorkItemID);
                ctxMainMenu.Items.Add(newMenu);
                ctxMainMenu.Refresh();
            }

            try
            {
                //ctxMainMenu.Refresh();
                foreach (string projectName in checkedProjects.Items)
                {
                    
                    newMenu = new ToolStripMenuItem(projectName);
                    //clear the menu before building a new one
                    newMenu.DropDown.Items.Clear();
                    ctxMainMenu.Refresh();
                    newMenu.DropDownItems.AddRange(GetWorkItemMenuesForProject(projectName));
                    //newMenu.DropDownItemClicked += new ToolStripItemClickedEventHandler(newMenuItem_DropDownItemClicked);
                    ctxMainMenu.Items.Insert(0,newMenu);
                    
                }
            }
            catch { }



****************

        private void newMenuItem_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            try
            {
                if (e.ClickedItem.Text.Contains("Stop Working"))
                {
                    StopWork();
                }
                else
                {
                    if (_currentWorkItemID > 0)
                    {
                        SwitchToWorkItemTo(int.Parse(e.ClickedItem.Text.Split(':')[0].ToString()));
                    }
                    else
                    {
                        _currentWorkItemID = int.Parse(e.ClickedItem.Text.Split(':')[0].ToString());
                        StartWork(_currentWorkItemID);
                    }
                }
                ctxMainMenu.Refresh();
            }
            catch { }
        }

Open in new window

0
Comment
Question by:brendanlefavre
  • 11
  • 11
22 Comments
 
LVL 96

Expert Comment

by:Bob Learned
ID: 34969350
Here is what I see:

1) You are creating a new instance of a ToolStripMenuItem, and then clearing the DropDown.Items, which is not needed, since you just creating a new instance.

newMenu = new ToolStripMenuItem(projectName);
newMenu.DropDown.Items.Clear();

2) I see where you are adding items to the main ContentMenuStrip, but not removing them, so that appears to be where they are getting duplicated.
0
 

Author Comment

by:brendanlefavre
ID: 34970185
how can i go about removing the duplicates?
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 34970392
If you describe your overall process (30000 meter view), I might be able to find a way, but right now I am not sure...

I would think that you could define all the menu items one time, and then toggle the visibility, but that doesn't sound quite right to me...
0
 

Author Comment

by:brendanlefavre
ID: 34970548
I have a WorkItemManager class that has two methods, one for getting projects, and another for getting work items.

the form code behind is where all of the logic is located

My overall goal is to populate the main menu with project items, and then submenu items for each project which are tasks.

there is an event handler attached to the task items that starts and stops a timer, which writes the time back to the data base via a method in the WorkItemManager class.


I have attached both classes to give an idea of where I started.

Cheers,
Brendan

 WorkItemManager.cs
frmMainConfiguration.cs
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 34970591
In frmMainConfiguration, I see the SetupMenu (that you showed above), which appears to set up the context menu.  It looks like it is only called once.  I don't see where duplicates could be added.

  private void SetupMenu()
        {
            ctxMainMenu.Items.Clear();

Open in new window

0
 

Author Comment

by:brendanlefavre
ID: 34970634
the duplicates appear after clicking on a task. if you click the task more than once, the duplicates will keep adding up. almost like its appending task items to the menu
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 34970660
There is a lot of code in frmMainConfiguration, so I don't know which control is associated with the "clicking on a task" action...
0
 

Author Comment

by:brendanlefavre
ID: 34970719
This is the code associated with the click event, it starts at line 186.

      private void newMenuItem_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            try
            {
                if (e.ClickedItem.Text.Contains("Stop Working"))
                {
                    StopWork();
                }
                else
                {
                    if (_currentWorkItemID > 0)
                    {
                        SwitchToWorkItemTo(int.Parse(e.ClickedItem.Text.Split(':')[0].ToString()));
                    }
                    else
                    {
                        _currentWorkItemID = int.Parse(e.ClickedItem.Text.Split(':')[0].ToString());
                        StartWork(_currentWorkItemID);
                    }
                }
                ctxMainMenu.Refresh();
            }
            catch { }
        }

Open in new window


Inside the SetupMenu method, and the in the foreach loop. I think this is the line where the duplicates are being generated.

newMenu.DropDownItems.AddRange(GetWorkItemMenuesForProject(projectName));

Open in new window

0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 34970747
Where are all the places where SetupMenu is called?  I don't see a call in newMenuItem_DropDownItemClicked...
0
 

Author Comment

by:brendanlefavre
ID: 34970954
the strange thing is SetupMenu is only called once, and that is in the LoadSettings method.

Is there a better approach for building the menu?
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 34971017
Can you attach a .png screen shot of what the menu looks like, please?
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 

Author Comment

by:brendanlefavre
ID: 34971120
I have attached a couple of screenshots
startup.png
before-click-event.png
after-click-event.png
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 34971305
OK, this is what I see now:

1) StopWork calls LoadSettings, and LoadSettings calls SetupMenu.

private void StopWork(bool SuppressNag)
        {
            try
            {
                SaveBank();
                _currentWorkItemID = 0;
                _currentWorkItemMinuteBank = 1;
                LoadSettings(false);
                ctxMainMenu.Refresh();
                ctxMainMenu.Hide();
                if (!SuppressNag)
                    Nag();
            }
            catch { }
        }

Open in new window


2) You are checking to see if the project items already exist in the context menu:

                    
                     if (!ctxMainMenu.Items.Contains(GetWorkItemMenuesForProject(projectName)))
                    {
                        newMenu.DropDownItems.AddRange(GetWorkItemMenuesForProject(projectName));
                    }

Open in new window


3) You are clearing the context menu items in the SetupMenu method, so I don't think that is what is causing the duplicates.  You might want to check the return for GetWorkItemMenuesForProject.

4) One debugging step that I prefer, since you can hover over the variable and see the debugging information is to store the result in an intermediate value:

ToolStripMenuItem[] menuItems = GetWorkItemMenuesForProject(projectName));
newMenu.DropDownItems.AddRange(menuItems);

Open in new window


Put a break point on the newMenu.DropDownItems, check the length for the ToolStripMenuItem array.
0
 

Author Comment

by:brendanlefavre
ID: 34972113
after stepping through the code, it appears that the method
private ToolStripMenuItem[] GetWorkItemMenuesForProject(string projectName)

Open in new window

is the cause. Each time it is called, the task item is added, even if the item already exists. is it possible to check if an item exists in the array, and only add the item if it does not exist?
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 34972383
The problem that I can see is that you can't use the Contains method, since it compares object references, and you have different objects, so it won't find a match, and add again.  

What .NET IDE version are you working with?
0
 

Author Comment

by:brendanlefavre
ID: 34972514
I'm using Visual Studio 2010, but I also have 2008 installed. Most of my development work has been in sharepoint, so winforms are a bit new to me.

Cheers,
Brendan  
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 34972615
Here is a proposal, using a Lambda expression (since you have 3.5 or higher):

        private ToolStripMenuItem[] GetWorkItemMenuesForProject(string projectName, ToolStripMenuItem parentMenu)
        {
            List<MyWorkItem> workItemList = wim.GetMyWorkItemsForProject(projectName);

             var query = from work in workItemList
                               join menu in parentMenu.DropDownItems
                                    on menu.Text equals work.Name into leftJoin
                               from newMenu in leftJoin.DefaultIfEmpty()
                               where newMenu != null
                               select newMenu;
        ...

Open in new window


Reference:

How to: Perform Left Outer Joins (C# Programming Guide)
http://msdn.microsoft.com/en-us/library/bb397895.aspx
0
 

Author Comment

by:brendanlefavre
ID: 34973529
thank you for the code sample

couple of questions

-do I only need to add a closing curly brace?

-I'm getting an error "A query body must end with a select clause or a group clause"      
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 34973625
I didn't set up a compilable project, so that code was developed in the question comment box.  My goal was to only give you a push towards LINQ queries.  

Can you show me the code that you have now?  You may have grabbed the code, before I added the "select"...
0
 

Author Comment

by:brendanlefavre
ID: 34974162
this is what I have so far

would it help if i attach the entire project?


 
    private ToolStripMenuItem[] GetWorkItemMenuesForProject(string projectName, ToolStripMenuItem parentMenu)
        {
            List<MyWorkItem> workItemList = wim.GetMyWorkItemsForProject(projectName);

             var query = from work in workItemList
                                join menu in parentMenu.DropDownItems
                                    on menu.Text equals work.Name into leftJoin
                                from newMenu in leftJoin.DefaultIfEmpty()
                                select new {work.projectName};

             foreach (var v in query)
             {

             } 

Open in new window

0
 
LVL 96

Accepted Solution

by:
Bob Learned earned 500 total points
ID: 34974477
Aha, this is a great opportunity for a LINQ lesson!!   This is like jumping right into the deep end of the pool, if you haven't worked with LINQ before!!

Scenario:
The development team has 3 developers.  Some of the developers wear two hats, and are part of the architect team.

Question:
Which developers are not architects also?

Example:

          
            List<string> developmentTeam = new List<string> { "John", "Bob", "Greg" };
            List<string> architectTeam = new List<string> { "John", "Jeff", "Alan" };

            var query = from dev in developmentTeam
                        join architect in architectTeam
                            on dev equals architect into merge
                        from result in merge.DefaultIfEmpty()
                        where result == null
                        select dev;

            List<string> differenceList = query.ToList();

Open in new window


Remarks:
To work with outer joins, you need to merge the results into another entity ("merge" in this case).  The DefaultIfEmpty will set the result value to null if a match isn't found.  The "where" condition tests for the null condition, which means only select a value if there isn't a match between development and architect names.
0
 

Author Closing Comment

by:brendanlefavre
ID: 35084453
your guidance helped me work through the code, and I learned something new along the way. The project that I inherited was loaded with different types of issues, and the menu was just one of them. I have decided to take the approach of starting over.

Cheers,
Brendan
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Flash (http://en.wikipedia.org/wiki/Adobe_Flash) has evolved over the years to where it has become a masterful tool for displaying content screen.  It has excellent layout placement, UI precision as well as rendering capabilities. This, along with t…
This document covers how to connect to SQL Server and browse its contents.  It is meant for those new to Visual Studio and/or working with Microsoft SQL Server.  It is not a guide to building SQL Server database connections in your code.  This is mo…
It is a freely distributed piece of software for such tasks as photo retouching, image composition and image authoring. It works on many operating systems, in many languages.
This demo shows you how to set up the containerized NetScaler CPX with NetScaler Management and Analytics System in a non-routable Mesos/Marathon environment for use with Micro-Services applications.

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now