问题描述
我在这段代码中没有使用任何线程,但是我有这个
跨线程操作无效:从创建该线程的线程之外的其他线程访问控件"txtStatus"."
当我单击表单上的连接"按钮时,请帮助我,谢谢您
Hi ,I didnt use any thread in this code but I have this
"Cross-thread operation not valid: Control ''txtStatus'' accessed from a thread other than the thread it was created on."
when I click the "Connect" button on the form,please help me,thank you
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
namespace ExampleNetworkAsyncTCPClient
{
public partial class Form1 : Form
{
private Socket client;
private byte[] data = new byte[1024];
private int size = 1024;
void Connected(IAsyncResult iar)
{
client = (Socket)iar.AsyncState;
try
{
client.EndConnect(iar);
txtStatus.Text = "Connected to " + client.RemoteEndPoint.ToString();
}
catch (SocketException)
{
txtStatus.Text = "Error connecting";
}
}
void ReceiveData(IAsyncResult iar)
{
Socket remote = (Socket)iar.AsyncState;
int rcv = remote.EndReceive(iar);
string stringData = Encoding.ASCII.GetString(data, 0, rcv);
lstList.Items.Add(stringData);
}
void SendData(IAsyncResult iar)
{
Socket remote = (Socket)iar.AsyncState;
int sent = remote.EndSend(iar);
remote.BeginReceive(data, 0, size, SocketFlags.None, new AsyncCallback(ReceiveData), remote);
}
public Form1()
{
InitializeComponent();
}
private void button3_Click(object sender, EventArgs e)
{
client.Close();
txtStatus.Text = "Disconnected";
}
private void cmdConnect_Click(object sender, EventArgs e)
{
txtStatus.Text = "Connecting...";
Socket newSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9050);
newSock.BeginConnect(ipep, new AsyncCallback(Connected), newSock);
}
private void cmdSend_Click(object sender, EventArgs e)
{
byte[] message = Encoding.ASCII.GetBytes(txtMessage.Text);
txtMessage.Clear();
client.BeginSend(message, 0, message.Length, SocketFlags.None, new AsyncCallback(SendData), client);
}
}
}
推荐答案
namespace RandomTest {
using System.Threading;
internal class ThreadWrapper {
internal class NumberGeneratedEventArgs : System.EventArgs {
internal NumberGeneratedEventArgs(int number) { this.fNumber = number; }
internal int Number { get { return fNumber; } }
int fNumber;
} //class NumberGeneratedEventArgs
internal ThreadWrapper(int sleepTime) {
this.thread = new Thread(this.Body);
this.sleepTime = sleepTime;
} //ThreadWrapper
internal void Start() { this.thread.Start(); }
internal void Abort() { this.thread.Abort(); }
internal void Pause() { this.waitHandle.Reset(); }
internal void Resume() { this.waitHandle.Set(); }
internal event System.EventHandler<NumberGeneratedEventArgs>
NumberGenerated;
void Body() {
int value = 0;
while (true) {
waitHandle.WaitOne();
if (NumberGenerated != null)
NumberGenerated.Invoke(this, new NumberGeneratedEventArgs(value));
value++;
Thread.Sleep(sleepTime);
} //loop
} //Body
Thread thread;
int sleepTime;
ManualResetEvent waitHandle = new ManualResetEvent(false); //non-signalled
} //ThreadWrapper
} //namespace RandomTest
现在,让我们以表格形式使用它.我故意将其全部放在一个文件中,并避免使用Designer,因此所有代码都放在一个位置:
Now, let''s use it in the form. I intentionally made it all in one file and avoided use of Designer, so all code would be in one place:
namespace RandomTest {
using System.Windows.Forms;
public partial class FormMain : Form {
const string ButtonStop = "&Stop";
const string ButtonStart = "&Start";
const int SleepTime = 500;
delegate void NumberAction(Label label, int value);
//in .NET version above 2.0 this line is not needed
//use System.Action<Label, int> instead
public FormMain() {
Padding = new Padding(10);
Button button = new Button();
button.Text = ButtonStart;
button.Dock = DockStyle.Bottom;
Controls.Add(button);
Label output = new Label();
output.Dock = DockStyle.Fill;
output.AutoSize = false;
Controls.Add(output);
button.Click += delegate(object sender, System.EventArgs eventArgs) {
if (running) {
button.Text = ButtonStart;
wrapper.Pause();
} else {
button.Text = ButtonStop;
wrapper.Resume();
} //if
running = !running;
}; //button.click
wrapper.NumberGenerated += delegate(object sender, ThreadWrapper.NumberGeneratedEventArgs eventArgs) {
output.Invoke(new NumberAction(delegate(Label label, int value) {
label.Text = value.ToString();
}), output, eventArgs.Number);
}; //wrapper.NumberGenerated
wrapper.Start();
this.Closing += delegate(object sender, System.ComponentModel.CancelEventArgs e) {
wrapper.Abort();
};
} //FormMain
bool running;
ThreadWrapper wrapper = new ThreadWrapper(SleepTime);
} //class FormMain
} //namespace RandomTest
我还尝试使用与仍在使用的C#v.2兼容的语法.在更高版本中,匿名委托的lambda语法非常有用.方法如下:
I also tried to use the syntax compatible with C# v.2, which is still used. In later versions, lambda syntax of anonymous delegates is highly beneficial. Here is how:
button.Click += (sender, eventArgs) => { /* ... */ };
这种语法有很多好处.首先,看一下处理程序:在这种情况下,您不需要使用参数.使用lambda语法,您甚至不需要查找参数类型-编译器从事件Click
的类型推断出它们.即使您需要使用一个或两个参数,Intellisense也会向您显示可以使用的那些类型的成员,但是您仍然不需要记住或找出参数名称.
There are many benefits of this syntax. First of all, look at the handler: you don''t need to use the parameters in this case. With lambda syntax, you don''t even need to look for parameters types — they are inferred by a compiler from the type of the event Click
. Even when you need to use one or both parameters, Intellisense will show you the members of those types you can use, but you still won''t need to remember or find out parameter names.
这篇关于AsyncCallback和线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!