我正在撰寫一個 C# 腳本來在網路上進行 ping 測驗。我大部分時間都在作業,除了寫入richtextbox的部分。在進行 ping 測驗時,我需要寫出結果。我知道它需要多執行緒,但我在過去的一周里一直試圖弄清楚它,但做不到。這是我的代碼,減去了不必要的部分。我遇到問題的部分是 RunPingTest 函式。我還將包含用于 IP 地址的示例 xml。所有按鈕和其他功能都按預期作業。
using System.Diagnostics;
using System.Windows;
using System.Xml.Linq;
using System.Collections.Generic;
using System.Net.NetworkInformation;
using System;
using System.Threading;
namespace NetTestingTool
{
public partial class NetTest : Window
{
static string dataFolder = "D:";
static readonly string configPath = dataFolder "\\ConfigFiles";
//get HostIPAddresses.xml
XElement GroupNames = XElement.Load(configPath "\\HostIPAddresses.xml");
bool testIsRunning = false;
//Start the initial GUI
public NetTest()
{
InitializeComponent();
//populate the dropdown
foreach (var groupElement in GroupNames.Elements("Group"))
{
if (groupElement.Attribute("name").Value != null)
{
dropDown.Items.Add(groupElement.Attribute("name").Value);
}
}
}
//********** Button Actions **********
//run the network test
public void BtnStart_Click(object sender, RoutedEventArgs e)
{
//clear richtextbox first
resultsBox.Document.Blocks.Clear();
//first, make sure the user has selected a group
if (dropDown.SelectedItem != null)
{
string HostSelection = (string)dropDown.SelectedItem;
//create a list of IP addresses based on group chosen
List<string> pingList = new List<string>();
foreach (var groupElement in GroupNames.Elements("Group"))
{
//resultsBox.AppendText(groupElement.Attribute("name").Value);
if (groupElement.Attribute("name").Value == HostSelection)
{
// resultsBox.AppendText(groupElement);
foreach (var hostSystem in groupElement.Elements("HostSystem"))
{
if (hostSystem.Attribute("IPAddress").Value != null)
{
pingList.Add(hostSystem.Attribute("IPAddress").Value);
}
}
}
}
/*Should this be outside BtnStart_Click?
currently cannot because it uses pingList*/
void RunPingTest(object? obj)
{
//do the ping test
resultsBox.AppendText("Doing the ping test \r"); //Just kidding, it isn't
foreach (var pingElement in pingList)
{
//this needs to be able to write to resultsBox as the ping happens (richtextbox)
Ping myPing = new Ping();
resultsBox.AppendText("Pinging " pingElement ". . . ");
PingReply reply = myPing.Send(pingElement, 2000); //ip and timeout
string results = reply.Status.ToString();
resultsBox.AppendText(results "\r");
}
resultsBox.AppendText("\r\n Finished ping testing");
}
}
}
//other buttons here
}
}
IP地址的xml:
<?xml version="1.0"?>
<Systems>
<Group name="Group1">
<HostSystem name="System1" IPAddress="1.1.1.1"> </HostSystem>
<HostSystem name="System2" IPAddress="2.2.2.2"> </HostSystem>
<HostSystem name="System3" IPAddress="3.3.3.3"> </HostSystem>
</Group>
<Group name="Group2">
<HostSystem name="System4" IPAddress="4.4.4.4"> </HostSystem>
<HostSystem name="System5" IPAddress="5.5.5.5"> </HostSystem>
<HostSystem name="System6" IPAddress="6.6.6.6"> </HostSystem>
</Group>
uj5u.com熱心網友回復:
好吧,在您發布的代碼中,您永遠不會呼叫該方法RunPingTest,這可能就是您RichTextBox永遠不會更新的原因。
但是,如果您想異步執行此操作,則Ping class包含一個使用許多多載呼叫的方法SendPingAsync,該多載回傳 aTask<PingReply>并允許您只使用async/await. 無需引入任何一種Thread或BackgroundWorker手動處理Dispatcher.
private async void BtnStart_Click(object sender, RoutedEventArgs e)
{
var pingList = new List<string>
{
"1.1.1.1",
"2.2.2.2",
"3.3.3.3",
"4.4.4.4"
};
resultsBox.Document.Blocks.Clear();
resultsBox.AppendText("Doing the ping test\r");
using (var ping = new Ping())
{
foreach (var ip in pingList)
{
resultsBox.AppendText($"Pinging {ip} . . . ");
PingReply reply = await ping.SendPingAsync(ip, 2000);
resultsBox.AppendText($"{reply.Status} \r");
}
}
}
重要的是使您的事件處理程式async void和await對SendPingAsync. 您可能還需要考慮在方法完成之前禁用“BtnStart”,否則用戶將能夠在 ping 測驗仍在運行時單擊它。
uj5u.com熱心網友回復:
您不能從 GUI 執行緒以外的執行緒訪問控制元件。
一個快速的解決方法是AppendText通過將主Dispatcher物件保存在建構式中并使用它在主執行緒上呼叫附加(使用BeginInvoke)來將您分派到主執行緒。
您可能應該改進的其他事情是不實體化多個Ping物件并且根本不使用富文本框,您所擁有的是日志條目行,這些行更好地建模為系結到ItemsControl.
編輯:也用于Path.Combine組合路徑,您的字串連接非常脆弱。
uj5u.com熱心網友回復:
我對您的設計和代碼有足夠的評論,但為了幫助您解決這里的問題,如何從執行緒更新 resultsBox:
if (resultsBox.InvokeRequired)
{
this.BeginInvoke((MethodInvoker)delegate()
{
// you can do anything to resultBox here (1)
});
}
else
{
// do it here (2)
}
為避免在 1 和 2 處重復代碼,請創建一個新方法 UpdateResultBox() 來放置所有邏輯,您的代碼將是:
if (resultsBox.InvokeRequired)
{
this.BeginInvoke((MethodInvoker)delegate()
{
UpdateResultsBox();
});
}
else
{
UpdateResultsBox();
}
private void UpdateResultsBox()
{
// put your logic here
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/475810.html
下一篇:WPF系結串列框選定項到文本框中
