0

我在 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)"
4

2 回答 2

3

ContactTile是在 UI 线程以外的线程中创建的,但是在AddContactTile您将其添加到mainPanel's我认为是 UI 线程的线程中。遵循这条规则“从创建控件的线程以外的线程调用控件是不安全的”,尝试ContactTile在 UI 线程中创建实例。

于 2013-06-13T22:09:15.493 回答
1

您可以在调用或从委托本身检查互斥锁mutex.WaitOne();之前使用互斥锁和调用。.BeginInvoke(...);

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

于 2013-06-13T21:36:23.477 回答