可以';t从服务器线程更新UI中的文本框
本文关键字:UI 更新 文本 线程 服务器 可以 | 更新日期: 2023-09-27 18:11:32
我试图在c#上编写一个带有UI的服务器程序。服务器是从后台worker->saparated线程调用的。在服务器中,我必须更新用户界面,了解在什么prot上连接了什么cient,以及其他一些参数。我知道我必须使用Invoke,我也读过它,但不知何故,我无法在代码中实现它。这是我的代码,感谢您的帮助:
enter code here
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.Runtime.InteropServices;
using System.Net.Sockets;
using System.Threading;
using System.IO;
using System.Configuration;
using System.Collections;
namespace WindowsFormsApplication1
{
public partial class ServerAppMainDisplay : Form
{
public Int32 local_port = 40000;
public int StopOrSrart = 0;
public string localIP = "?";
public string myHostName = "?";
public string ServerIP = "Server IP: ";
public string DefaultPort = "Listening on default port: ";
public string MachineName = "Machine Name: ";
public static bool ThrdState = false;
public static bool TxtBoxVsblty = false;
public ServerAppMainDisplay()
{
InitializeComponent();
textBox2.Text = DefaultPort;
textBox1.Text = ServerIP;
textBox3.Text = MachineName;
textUpdate.ShowDialogs();
}
private void UpdateText(string text)
{
// Set the textbox text
textBox5.Text = text;
}
private void button1_Click(object sender, EventArgs e)
{
myHostName = Dns.GetHostName().ToString();
localIP = Dns.Resolve(myHostName).AddressList[0].ToString();
textBox1.Text = ServerIP + localIP;
textBox3.Text = MachineName + myHostName;
textBox2.Text = DefaultPort + local_port.ToString();
backgroundWorker1.RunWorkerAsync();
}
private void button2_Click(object sender, EventArgs e)
{
//Data Log txt
}
private void button3_Click(object sender, EventArgs e)
{
//Data Log Excel
}
private void button4_Click(object sender, EventArgs e)
{
DialogResult dialogResult = MessageBox.Show("Are you sure you want to stop server application?",
"Stop server application", MessageBoxButtons.YesNo);
if (dialogResult == DialogResult.Yes)
{
textBox2.Text = DefaultPort;
textBox1.Text = ServerIP;
textBox3.Text = MachineName;
myTCPServer.thread.Abort();
myTCPServer.listener.Stop();
myTCPServer.DefSoc.Dispose();
for (int i = 1; i < 10; i++)
{
if (myTCPServer.Connection[i].portFlag)
{
myTCPServer.Connection[i].slistener.Stop();
myTCPServer.Connection[i].socket.Dispose();
}
}
ThrdState = true;
TxtBoxVsblty = false;
}
if (dialogResult == DialogResult.No) return;
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
myTCPServer.myMain();
}
private void button5_Click(object sender, EventArgs e)
{
DialogResult dialogResult = MessageBox.Show("Are you sure you want to exit server window application?",
"Exit server window application", MessageBoxButtons.YesNo);
if (dialogResult == DialogResult.Yes)
{
backgroundWorker1.Dispose();
backgroundWorker1.CancelAsync();
myTCPServer.thread.DisableComObjectEagerCleanup();
myTCPServer.thread.Abort();
this.Close();
Application.Exit();
}
if (dialogResult == DialogResult.No) return;
}
}
public class myTCPServer
{
public static Socket DefSoc;
public static Thread thread = new Thread(new ThreadStart(Service));
public static TcpListener listener;
public struct Connection_s
{
public int port;
public bool portFlag;
public Socket socket;
public TcpListener slistener;
};
public static myTCPServer.Connection_s[] Connection = new myTCPServer.Connection_s[10];
public const int DefaultPort = 40000;
public static void myMain()
{
if (!WindowsFormsApplication1.ServerAppMainDisplay.ThrdState)
myTCPServer.thread.Start();
else
{
myTCPServer.thread = new Thread(new ThreadStart(Service));
myTCPServer.thread.Start();
}
}
public static void Service()
{
for (int i = 1; i < 10; i++)
{
Connection[i].portFlag = false;
Connection[i].port = DefaultPort + i;
}
myTCPServer.listener = new TcpListener(DefaultPort);
myTCPServer.DefSoc = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
while (true)
{
byte[] SndBfr;
string str;
myTCPServer.listener.Start();
if (myTCPServer.listener.Pending())
{
DefSoc = myTCPServer.listener.AcceptSocket();
for (int i = 1; i < 10; i++)
{
if (Connection[i].portFlag == false)
{
Thread.Sleep(10);
str = "<" + Connection[i].port as string;
SndBfr = System.Text.Encoding.UTF8.GetBytes(str);
DefSoc.Send(SndBfr);
Thread.Sleep(10);
Connection[i].slistener = new TcpListener(Connection[i].port);
Connection[i].slistener.Start();
Connection[i].socket = Connection[i].slistener.AcceptSocket();
Connection[i].portFlag = true;
yourTextBox.Invoke(new UpdateTextCallback(this.UpdateText),
new object[]{”Text generated on non-UI thread.”});
DefSoc.Disconnect(true);
DefSoc.Dispose();
myTCPServer.listener.Stop();
myTCPServer.listener = new TcpListener(DefaultPort);
myTCPServer.DefSoc = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
break;
}
}
}
Thread.Sleep(10);
for (int i = 1; i < 10; i++)
{
if (Connection[i].portFlag == true)
{
int SndRslt = 0;
str = DateTime.Now.ToString(@"MM'/dd'/yyyy h':mm tt");
try
{
SndRslt = Connection[i].socket.Send(System.Text.Encoding.UTF8.GetBytes("+" + str));
}
catch (SocketException) { }
if (SndRslt <= 0)
{
try
{
Connection[i].portFlag = false;
Connection[i].socket.Disconnect(true);
Connection[i].slistener.Stop();
}
catch (SocketException) { }
}
}
}
}
}
}
}
将UpdateText(string text)
更改为:
private void UpdateText(string text)
{
if(textBox5.InvokeRequired)
{
Action a = () => UpdateText(text);
Invoke(a);
}
else
textBox5.Text = text;
}
如果需要,这将调用文本框。
来自MSDN 的Invoke
Invoke方法向上搜索控件的父链,直到它如果当前控件的底层窗口句柄尚不存在。如果没有如果找不到合适的句柄,Invoke方法将抛出例外通话中出现的异常情况为传播回调用者。
您应该为跨线程选择"MethodInvoker"[此外,为了确保"Method"在GUI线程上执行]
也许这会有所帮助:
MethodInvoker method = delegate{
yourTextBox.Text = "the text you need";
};
if (InvokeRequired) // You may skip this
BeginInvoke(method);
调用更新UI的函数的委托,并在函数中使用InvokeRequired检查是否需要调用该委托。
示例:
Imports System.Management
Private watcher As New ManagementEventWatcher
//delegate to udater UI function
Delegate Sub SetItemCallback(ByVal item As ListViewItem)
Private item1 As ListViewItem
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim query As New WqlEventQuery("Win32_ProcessStartTrace")
watcher.Query = query
AddHandler watcher.EventArrived, AddressOf EventWorker
watcher.Start()
End Sub
'This method start when event arrived. It's invoked from another thead. (not UI thread)
Public Sub EventWorker(ByVal sender As Object, ByVal e As System.Management.EventArrivedEventArgs)
Try
Dim mbo As ManagementBaseObject = e.NewEvent
For Each p As PropertyData In mbo.Properties
item1 = New ListViewItem(p.Name)
If p.Value IsNot Nothing Then : item1.SubItems.Add(p.Value.ToString)
Else : item1.SubItems.Add(String.Empty)
End If
'updates de UI
Me.SetItem(item1)
Next
Catch ex As Exception
Console.WriteLine(ex.Message)
End Try
End Sub
'If InvokeRequired (no UI thread) create the delegate and invoke it else update the UI
Private Sub SetItem(ByVal itm As ListViewItem)
If Me.ListView1.InvokeRequired Then
Dim d As New SetItemCallback(AddressOf SetItem)
Me.Invoke(d, New Object() {itm})
Else
ListView1.Items.Add(itm)
End If
End Sub
Private Sub Form1_FormClosed(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
watcher.Stop()
End Sub