為什么方法1不能正確執行,通過Action <'string'> updateMsgAction,給ListBox添加訊息,但是方法2可以正確執行?
我嘗試使用方法 3 BeginInvoke(Delegate, Object[])
,編譯器顯示錯誤。
我希望方法 #2 可以像方法 #1 一樣成為需要更新訊息時呼叫的方法。
方法1:UpdateMsg使用Action<string>
private Action<string> updateMsgAction;
public void UpdateMsg()
{
updateMsgAction = new Action<string>( (s) =>
{
MsgList.Items.Add(s);
if (MsgList.Items.Count > 1000)
{
MsgList.Items.RemoveAt(0);
}
});
}
方法3:使用BeginInvoke(Delegate, Object[])
public delegate void MyDelegate(ListBox myControl, string myMessage);
public void DelegateMethod(ListBox myControl, string myMsg)
{
myControl.Items.Add(myMsg);
}
MQTT 服務器啟動:
public async void StartMqttServer()
{
try
{
var mqttFactory = new MqttFactory();
if (mqttServer == null)
{
var mqttServerOptions = new MqttServerOptionsBuilder().WithDefaultEndpoint().WithDefaultEndpointPort(int.Parse(txtBoxPort.Text)).Build();
mqttServer.ClientConnectedHandler = new MqttServerClientConnectedHandlerDelegate(OnMqttServerClientConnected);
mqttServer.ClientDisconnectedHandler = new MqttServerClientDisconnectedHandlerDelegate(OnMqttServerClientDisconnected);
mqttServer.ClientSubscribedTopicHandler = new MqttServerClientSubscribedTopicHandlerDelegate(OnMqttServerCleitnSubScribedTopic);
mqttServer.ClientUnsubscribedTopicHandler = new MqttServerClientUnsubscribedTopicHandlerDelegate(OnMqttServerCleitnUnsubScribedTopic);
mqttServer.ApplicationMessageReceivedHandler = new MqttApplicationMessageReceivedHandlerDelegate(OnMqttServerApplicationMessageReceived);
await mqttServer.StartAsync(mqttServerOptions);
MsgList.BeginInvoke(updateMsgAction, "MQTT Server is started."); //Method 1
/*MsgList.BeginInvoke(new Action<string>((s) =>
{ MsgList.Items.Add(s); }), "MQTT Server is started."));*/ //Method 2
//MsgList.BeginInvoke(new MyDelegate(DelegateMethod), "MQTT Server is started.")); //Method 3
}
}
catch(Exception ex)
{
MsgList.BeginInvoke(updateMsgAction, "MQTT Server start fail."));
}
}
OnMqttServerApplicationMessageReceived:
public void OnMqttServerApplicationMessageReceived(MqttApplicationMessageReceivedEventArgs e)
{
// Method 1
MsgList.BeginInvoke(updateMsgAction,
String.Format("Client[{0}]>> Topic:{1} Payload:{2} Qos:{3} Retain:{4}",
e.ClientId, e.ApplicationMessage.Topic, e.ApplicationMessage.Payload.ToString(),
e.ApplicationMessage.QualityOfServiceLevel, e.ApplicationMessage.Retain));
}
uj5u.com熱心網友回復:
BeginInvoke 用于在創建控制元件的執行緒中執行一些代碼。這是在他們自己的執行緒中(通常在主執行緒中)強制更新控制元件,否則您會遇到例外。因此,您的使用或 BeginInvoke 是正確的。
問題是,當您在主執行緒中運行并且能夠更新控制元件時,您在操作中委派更新。該操作在其他執行緒中運行,您正在“取消”de BeginInvoke 并獲得預期的例外,試圖更新其他執行緒中的控制元件。
我將 SynchronizationContext 用于此類事情。在表單的代碼中,添加一個變數:
private static SynchronizationContext Context;
更新:并在建構式中初始化:
public YourForm()
{
this.InitializeComponent();
Context = SynchronizationContext.Current;
// Other code
}
添加這個方法:
private static void RunInMainThread(Action operation)
{
if (Context != SynchronizationContext.Current)
{
Context.Post(o => operation(), null);
}
else
{
operation();
}
}
如果您已經在主執行緒中運行,則您的代碼將立即運行。在其他情況下,Post 操作在主執行緒中異步運行。您可以改用 Send 或 Post 來同步運行。并在您需要訪問控制元件時使用它:
public void OnMqttServerApplicationMessageReceived(MqttApplicationMessageReceivedEventArgs e)
{
var msg = string.Format(
"Client[{0}]>> Topic:{1} Payload:{2} Qos:{3} Retain:{4}",
e.ClientId,
e.ApplicationMessage.Topic,
e.ApplicationMessage.Payload.ToString(),
e.ApplicationMessage.QualityOfServiceLevel,
e.ApplicationMessage.Retain);
RunInMainThread(() =>
{
MsgList.Items.Add(msg);
// Other code...
}
}
您可以為 SynchronizationContext 而不是 RunInMainThread 創建擴展方法(發布和發送)并在您的專案中重用。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/450353.html
