|
|
Font Size [large, medium, and small] |
Problem description: The windows program on the client uses webmethod to obtain a list of system information from the server. There are multiple messages in the information list. When the system message time meets the requirements, use a custom messageform to show the system message. Messageform is a winform containing webbrowser. The show messageform call is executed in a timer. The following error occurs when you call the showmessage operation.
Error code:
Private void btntests_click (Object sender, eventargs E) { Datarow ROW = (New datatable (). newrow (); System. Threading. Timer timer = new system. Threading. Timer ( New system. Threading. timercallback (showmessageforms ), Row, 0, 30000 ); } Private void showmessageforms (Object status) { (New messageform (). Show (); } |
An error occurred when new messageform calls its initializecomponent () method. If you delete the webbrowser control on messageform, the program can show the form normally without errors. Problem investigation: From the program error information, we can see that it may be an ActiveX suite problem. ActiveX webbrowser requires that the current thread is a single-thread apartment. The webbrowser COM component requires that the current thread be a single-suite, while the thread from system. Threading. Timer is a mtathread multi-suite. A problem occurs. Solution: Solution 1: Use a new thread to start messageform and set the apartmentstate of this thread to sta
Private void btntestt_click (Object sender, eventargs E) { Datarow ROW = (New datatable (). newrow (); System. Threading. Timer timer = new system. Threading. Timer ( New system. Threading. timercallback (showmessageformt ), Row, 0, 300000 ); }Private void showmessageformt (Object status) { System. Threading. Thread thread = new system. Threading. Thread ( New system. Threading. parameterizedthreadstart (showmessage )); Thread. setapartmentstate (system. Threading. apartmentstate. Sta ); Thread. Start (Status ); } Private void showmessage (Object status) { System. Windows. Forms. application. Run (New messageform ()); (New messageform (). showdialog (); } |
Solution 2: Find the main UI thread and schedule it with the main UI thread. Show messageform
Private void btntestg_click (Object sender, eventargs E) { Datarow ROW = (New datatable (). newrow (); System. Threading. Timer timer = new system. Threading. Timer ( New system. Threading. timercallback (showmessageformg ), Row, 0, 300000 ); } Private delegate void showmessagehandler (datarow row ); Private void showmessageformg (Object status) { If (system. Windows. Forms. application. openforms [0]. invokerequired) { System. Windows. Forms. application. openforms [0]. Invoke (New showmessagehandler (showmessageformg), new object [] {status }); Return; } Showmessage (Status ); } Private void showmessage (Object status) { (New messageform (). showdialog (); } |
In the example, datarow ROW = (New able (). newrow (); has no practical significance. In actual code, showmessage requires a datarow to draw messages. In the sample code, datarow is only used to simulate the actual environment and has no practical significance.
Add another method public partial class Form1 : Form {
private void button1_Click(object sender, EventArgs e) { System.Threading.Thread s = new System.Threading.Thread(new System.Threading.ThreadStart(test)); s.ApartmentState = System.Threading.ApartmentState.STA; s.Start(); }
public void test() { this.Invoke(new EventHandler(this.invokeTest)); } public void invokeTest(object sender,EventArgs e) { System.Windows.Forms.WebBrowser wb = new WebBrowser(); this.Controls.Add(wb); } public Form1() { InitializeComponent(); } } |