从单独的线程添加菜单项

发布于 2024-08-11 17:22:35 字数 1174 浏览 2 评论 0原文

我正在一个单独的线程中创建菜单项,并将它们添加到主线程中创建的菜单中。我正在使用 Invoke 来实现这一点。出现“值不在预期范围内”异常。

            //creating new thread
            Thread thread = new Thread(LoadRecentTasks);
            thread.IsBackground = true;
            thread.Start();

    private void LoadRecentTasks()
    {
        EntryCollection recentEntries = Entry.GetRecentEntries(10);
        foreach (Entry entry in recentEntries)
        {
            MenuItemPlus menuItem = new MenuItemPlus();
            menuItem.Text = entry.GetShortDescription(28);
            menuItem.Click += recentTasksMenuItem_Click;
            menuItem.Tag = entry;
            AddRecentMenuItem(menuItem);
        }
    }

    private void AddRecentMenuItem(MenuItemPlus menuItem)
    {
        if (InvokeRequired)
        {
            BeginInvoke(new CallbackDelegate<MenuItemPlus>(AddRecentMenuItem), menuItem);
        }
        else
        {
            menuItemRecent.MenuItems.Add(menuItem); //<-- exception thrown here
        }
    }

    delegate void CallbackDelegate<T>(T t);

有什么建议吗?

更新:我也尝试过调用 - 相同的结果。

menuItemRecent 是作为表单初始化例程的一部分创建的。线程在表单的激活事件上启动

I'm creating menu items in a separate thread and adding them to the menu created in the main thread. I'm using Invoke for that. Getting "Value does not fall within the expected range" exception.

            //creating new thread
            Thread thread = new Thread(LoadRecentTasks);
            thread.IsBackground = true;
            thread.Start();

    private void LoadRecentTasks()
    {
        EntryCollection recentEntries = Entry.GetRecentEntries(10);
        foreach (Entry entry in recentEntries)
        {
            MenuItemPlus menuItem = new MenuItemPlus();
            menuItem.Text = entry.GetShortDescription(28);
            menuItem.Click += recentTasksMenuItem_Click;
            menuItem.Tag = entry;
            AddRecentMenuItem(menuItem);
        }
    }

    private void AddRecentMenuItem(MenuItemPlus menuItem)
    {
        if (InvokeRequired)
        {
            BeginInvoke(new CallbackDelegate<MenuItemPlus>(AddRecentMenuItem), menuItem);
        }
        else
        {
            menuItemRecent.MenuItems.Add(menuItem); //<-- exception thrown here
        }
    }

    delegate void CallbackDelegate<T>(T t);

Any suggestions?

UPDATE: i've tried it with Invoke too - same result.

menuItemRecent is created as part of the form's initialization routine. The thread is started on form's Activated event

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梨涡少年 2024-08-18 17:22:35

我假设当控件未完全创建时会发生这种情况,导致 InvokeRequired 给您错误的读数。

      /// <summary>
  /// It's possible for InvokeRequired to return false when running in background thread.
  /// This happens when unmanaged control handle has not yet been created (need to throw).
  /// This can also happen when control is created on background thread (need to debug.assert).
  /// </summary>
  /// <param name="control">Control to check against.</param>
  public bool InvokeRequired(Control control)
  {
     return InvokeRequired(control, false);
  }

  /// <param name="backgroundControl">If set to true, will not assert when control on background thread. </param>
  public bool InvokeRequired(Control control, bool controlOnBackgroundByDesign)
  {
     if (control.InvokeRequired)
        return true;

     if (!control.IsHandleCreated)
        Debug.WriteLine("Control access issue: Underlying control handle has not been created yet.  At this point in time cannot reliably test if invoke is required.");

     if (!controlOnBackgroundByDesign)
     {
        // Check for control on background thread.
        if(!this.IsOnUiThread)
           Debug.WriteLine("Control access issue: It's recommended that all controls reside on a single foreground thread.");
     }

     // At this point, program is executing on control's thread.
     return false;
  }

I assume this happens when control is not fully created, causing InvokeRequired to give you a false reading.

      /// <summary>
  /// It's possible for InvokeRequired to return false when running in background thread.
  /// This happens when unmanaged control handle has not yet been created (need to throw).
  /// This can also happen when control is created on background thread (need to debug.assert).
  /// </summary>
  /// <param name="control">Control to check against.</param>
  public bool InvokeRequired(Control control)
  {
     return InvokeRequired(control, false);
  }

  /// <param name="backgroundControl">If set to true, will not assert when control on background thread. </param>
  public bool InvokeRequired(Control control, bool controlOnBackgroundByDesign)
  {
     if (control.InvokeRequired)
        return true;

     if (!control.IsHandleCreated)
        Debug.WriteLine("Control access issue: Underlying control handle has not been created yet.  At this point in time cannot reliably test if invoke is required.");

     if (!controlOnBackgroundByDesign)
     {
        // Check for control on background thread.
        if(!this.IsOnUiThread)
           Debug.WriteLine("Control access issue: It's recommended that all controls reside on a single foreground thread.");
     }

     // At this point, program is executing on control's thread.
     return false;
  }
我只土不豪 2024-08-18 17:22:35

嗯嗯。每当我调用 BeginInvoke 时,我总是这样做:

BeginInvoke(new CallbackDelegate<MenuItemPlus>(AddRecentMenuItem), new object[]{menuItem});

IIRC 正确,我总是使用对象数组,因为过去没有它我会遇到奇怪的异常。

Hmmmm. Whenever I call BeginInvoke I always do this instead:

BeginInvoke(new CallbackDelegate<MenuItemPlus>(AddRecentMenuItem), new object[]{menuItem});

IIRC correctly I always use the object array because without it in the past I've got weird exceptions.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文