在多事件处理期间,跨线程操作无效

时间:2013-06-13 21:20:42

标签: c# multithreading winforms user-interface

我在Windows窗体应用程序中遇到UI问题。我知道互联网上有关于这个问题的无数帖子,但我仍然找不到合适的解决方案。

我有这个方法:

private void AddContactTile(ContactTile c)
{
    if (mainPanel.InvokeRequired)
    {
        AddContactTileDelegate ctdelegate = new AddContactTileDelegate(AddContactTile);
        mainPanel.BeginInvoke(ctdelegate, c);
    }
    else
    {
        mainPanel.Controls.Add(c);
    }
}

和这个方法:

private void ChangeTileStatus(string userid)
{
    ContactTile tile = contactTiles.Find(x => x.Key == userid).Value;
    if (tile.statusLabel.InvokeRequired)
    {
        ChangeTileStatusDelegate ctsdelegate = new ChangeTileStatusDelegate(ChangeTileStatus);
        tile.statusLabel.BeginInvoke(ctsdelegate, userid);
    }
    else
    {
        if (contacts.ContainsKey(userid))
        {
            tile.statusLabel.Visible = contacts[userid].IsAvailable;
            tile.Refresh();
        }
    }
}

这两个都在事件处理程序中调用。现在,因为可能同时引发事件,所以我在statusLabel方法的AddContactTile控件上收到了无效的跨线程操作消息。

有没有人知道如何正确同步这些访问?感谢。

AddContact方法的代码:

public void AddContact(FacebookUser user)
{
    contacts[user.id].DisplayPictureAvailable += new EventHandler<UserEventArgs>(Contacts_DisplayPictureAvailable);
    contacts[user.id].StatusChanged += new EventHandler<UserEventArgs>(Contacts_StatusChanged);
    ContactTile c = new ContactTile(user.name, user.id) { Location = new Point(0, contactTiles.Count == 0 ? 0 : contactTiles.Last().Value.Bounds.Bottom) };
    contactTiles.Add(new KeyValuePair<string, ContactTile>(user.id, c));
    AddContactTile(c);
}

堆栈追踪:

StackTrace  "   at System.Windows.Forms.Control.get_Handle()   at     
System.Windows.Forms.Control.UpdateChildZOrder(Control ctl)   at 
System.Windows.Forms.Control.WmCreate(Message& m)   at 
System.Windows.Forms.Control.WndProc(Message& m)   at 
System.Windows.Forms.Label.WndProc(Message& m)   at 
System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)"

2 个答案:

答案 0 :(得分:3)

ContactTile是在UI线程以外的线程中创建的,但是在AddContactTile中你将它添加到mainPanel's线程中,我认为它是UI线程。遵循此规则"It is unsafe to call a control from a thread other than the one that created the control",尝试在UI线程中创建ContactTile个实例。

答案 1 :(得分:1)

您可以在拨打mutex.WaitOne();之前使用互斥锁并拨打.BeginInvoke(...);,或者从代表本身检查互斥锁。

http://msdn.microsoft.com/en-us/library/system.threading.mutex.aspx