简体   繁体   中英

WPF contextmenu is slow with many items - how can I speed it up?

I have found the context menu takes over 10 seconds to display when I have 10,000 items in it, I'd like to make this faster (eg less than 1 second)

Here is my test code that shows the context menu slowness directly:

private void button1_Click(object sender, RoutedEventArgs e)
        {            
            ContextMenu cm = new ContextMenu();

            for (int i = 0; i < 1000; i++)
            {
                MenuItem mi = new MenuItem();
                mi.Header = "test";                 // this is HOT - 3%
                mi.Tag = this;                      // cold
                for (int j = 0; j < 10; j++)
                {
                    MenuItem mi2 = new MenuItem();  // this is HOT - 1%
                    mi2.Header = "test";            // this is HOT - 12%
                    mi2.Tag = this;                 // cold
                    mi.Items.Add(mi2);              // this is HOT - 6%
                }
                cm.Items.Add(mi);                   // this is HOT - 3%
            }
            cm.IsOpen = true;                       // this is HOT - 72%
        }

According to performance profilers I've used, the cm.IsOpen is taking most of the time - but setting the mi.Header is also significant.

It's going to be a poor user experience having 1k items at a single level, but how to make context menus with lots\\expensive items more responsive, is a fair question.

The general pattern I use is to initially create my menu with dummy sub-menus. The dummy sub-menus have a single place-holder menu item and I hook the sub-menu opening event. In the event handler I remove the place-holder menu item and add the real items in.

This pattern allows sub-menus to be created on demand and only if the sub-menu is actually opened. In other words it makes your menu dynamic meaning you do not have to create everything up-front, nor create hundreds of sub-menus which will not be opened.

This pattern would reduce your initial menu item count from 10k items to 1k for the example above. This should get you down to ~1 second.

Again 10k menu items with 1k in the root is pretty much unusable in terms of UX. I hope this is just a thought experiment! :)

Example

        ContextMenu cm = new ContextMenu();

        for (int i = 0; i < 1000; i++)
        {
            MenuItem mi = new MenuItem();
            mi.Header = "test";
            mi.Tag = this;

            object dummySub = new object();
            mi.Items.Add(dummySub);
            cm.Items.Add(mi);

            mi.SubmenuOpened += delegate
            {
                mi.Items.Clear();

                for (int j = 0; j < 10; j++)
                {
                    MenuItem mi2 = new MenuItem();
                    mi2.Header = "test";
                    mi2.Tag = this;
                    mi.Items.Add(mi2);
                }
            };
        }

        cm.IsOpen = true;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM