WPF上下文菜单很慢,有很多项目 - 我怎样才能加快速度?

时间:2011-01-13 22:43:38

标签: c# wpf contextmenu

我发现当我有10,000个项目时,上下文菜单需要10秒以上显示,我想让它更快(例如不到1秒)

这是我的测试代码,直接显示上下文菜单的慢度:

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%
        }

根据我使用的性能分析器,cm.IsOpen占用大部分时间 - 但设置mi.Header也很重要。

1 个答案:

答案 0 :(得分:7)

在一个级别上拥有1k项目的用户体验会很差,但是如何使用大量\昂贵的项目提高响应性的上下文菜单是一个公平的问题。

我使用的一般模式是最初创建带有虚拟子菜单的菜单。虚拟子菜单有一个占位符菜单项,我挂钩子菜单打开事件。在事件处理程序中,我删除了占位符菜单项并添加了真实项目。

此模式允许按需创建子菜单,并且只有在实际打开子菜单时才能创建子菜单。换句话说,它使您的菜单动态化意味着您不必预先创建所有内容,也不必创建数百个不会打开的子菜单。

对于上面的示例,此模式会将初始菜单项数从10k项减少到1k。这应该会让你减少到1秒钟。

根据用户体验,在根目录中有1k的10k菜单项几乎无法使用。我希望这只是一个思想实验! :)

示例

        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;