【发布时间】:2011-04-18 21:23:09
【问题描述】:
问了好久,先总结一下,
- 我的 Messenger 项目有一个 Client 类。
- 我的 Client 类有一个 Socket。
- 我使用它的 BeginReceive 方法从服务器获取消息。
- 在 BeginReceive 的异步回调中,我使用 EndReceive 获取消息。
- 当我收到消息时,我会触发带有消息本身的 MessageReceived 事件。
- 我在消息表单中使用了这个客户端类。
- 在消息形式中,我可以通过将方法附加到 Client.MessageReceived 来获取接收到的消息。
- 为此我使用 OnMessageReceived 方法。
- 收到消息后,我可以在 TextBox(使用 Control.Invoke)或 MessageBox 上显示它。
- 我还可以在 OnMessageReceived 中的 TabControl 中添加一个新选项卡。
- 当我尝试初始化 WebBrowser 控件时,我得到了 ThreadStateException。
- 我用来显示消息的控件来自 WebBrowser 控件,所以我需要它。
- Threading.Thread.CurrentThread.ThreadState 为“背景”。
我认为您不需要详细信息,但您可以在下面找到我最初打算发布的详细问题。
非常感谢。
我正在使用 Net.Socket 的异步方法处理一个信使项目(服务器是 Windows 服务,客户端是 Windows 窗体应用程序)。 我在 Socket.BeginReceive 的回调中触发客户端的 MessageReceived 事件; 直到这里,一切都是我希望他们成为的样子。
我在我的表单中使用 MessageReceived 事件(两个人互相写信的事件)我可以使用 Control.Invoke 方法(如果需要)对 UI 做任何我想做的事情,但有一个烦人的异常。
我在表单中有选项卡式对话,因此当消息到达时,我会检查是否与发件人有打开的对话(选项卡)。如果是,我选择该选项卡并显示消息。如果不是,我创建一个新的 ConversationTab。
现在,如果这个问题太长,或者我无法充分解释自己,我很抱歉。英语不是我的第一语言,这是我在 Stack Overflow 上的第一个问题。 所以,这里是对话标签:
public class ConversationTab : TabPage
{
public User Friend { get; private set; }
public MessageBrowser MessageBrowser { get; private set; }
public ConversationTab(User friend) : base(friend.DisplayName)
{
Friend = friend;
MessageBrowser = new MessageBrowser();
Controls.Add(MessageBrowser);
MessageBrowser.Dock = DockStyle.Fill;
}
}
MessageBrowser 派生自 WebBrowser,我使用它的原因是因为我无法使用 RichTextBox 对“每条消息”应用自定义样式(颜色、字体、大小)。 RichTextBox.SelectedColor 并不总是有效,或者我无法使其按预期工作。 MessageBrowser 让我改用 CSS。跑题了?对不起。
这是我在 MessageReceived 事件触发时调用的 NewConversation 方法:
public void NewConversation(User friend)
{
ConversationTab tab = Conversations.FirstOrDefault(c => c.Friend.Id == friend.Id);
if (tab != null)
ActiveConversation = tab;
else
{
tab = new ConversationTab(friend);
// add tab to TabControl
}
// bla
}
“Conversations”获取 TabControl 的标签页,“ActiveConversation”获取或设置 TabControl 的 SelectedTab 属性。 我创建这些属性的重点主要是内部的线程安全逻辑。
所以问题是:它在上述代码的“tab = new ConversationTab(friend)”部分抛出了 ThreadStateException。它是第一个代码的“MessageBrowser = new MessageBrowser()”部分,也是MessageBrowser的构造函数。我之所以没有提供 MessageBrowser 的构造函数代码是因为在执行任何内部代码行之前引发了异常(这是关于 WebBrowser 的构造函数,当我尝试初始化 WebBrowser 时也会出现此异常。) 实际上我什至没有得到异常,应用程序只是在那里关闭而没有通知我任何事情。当我尝试在 Watch 窗口中的 ConversationTab 的构造函数上调用“MessageBrowser = new MessageBrowser()”时看到了异常。
我对使用线程和异步方法有点陌生。 MSDN 说:
ThreadStateException 由由于线程当前状态而无法执行请求操作的方法引发。
在我的例子中,线程的状态是“Background”。 我不知道我做错了什么。
非常感谢您阅读全文,如果您能提供帮助,我们将更加感谢您。
【问题讨论】:
-
你使用
Control.Invoke()调用那个NewConversation方法吗? -
其实没有,我没用过。我认为 InvokeRequired 足以决定我是否需要使用 Invoke。好吧,后台线程是 MTA,并且不会阻止 InvokeRequired 返回 true(为什么应该这样做?)所以我使用了我的 Form(在 STA 线程上运行)的 Invoke 方法来封装进程。谢谢。
标签: c# multithreading sockets asynchronous