从 SQL 数据库中检索数据并使用动态创建的标签显示 Ping 结果
Retrieve data from SQL database and use dynamically created Labels to show Ping results
我需要在动态创建的标签中显示我的 SQL 数据库中的两个字段。因此,对于数据库中的每个条目,它都需要将其显示在彼此下方标签中的主要 window 上。但它没有显示标签中的信息。
所以这就是需要发生的事情。
用户将信息保存到 SQL 数据库(主机名、IP 地址和设备)
在主屏幕上(windows)然后需要这样显示:
服务器 1 192.168.x.x“Ping 结果”
这是我目前拥有的代码(这还不包括 ping 结果标签)
private void AddDynamicLabels()
{
string ConString = @"Data Source=PC\SQL;Initial Catalog=PingMonitorDB;Integrated Security=True";
SqlConnection con = new SqlConnection(ConString);
string CmdString = "SELECT host, ip FROM addhosts";
SqlCommand cmd = new SqlCommand(CmdString, con);
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
Label lbl = new Label();
lbl.Visible = true;
lbl.Text = reader["host" + "ip" + " "].ToString();
lbl.BackColor = System.Drawing.Color.Orange;
this.Controls.Add(lbl);
}
con.Close();
}
因此,对于添加的每个条目,理论上应该如下所示:
Server 1 192.168.x.x "ping reply"
Server 2 192.168.x.x "ping reply"
Server 3 192.168.x.x "ping reply"
....
etc
编辑
private async void frmMainWindow_Load(object sender, EventArgs e)
{
SqlConnection cnn = new SqlConnection(@"Data Source=PC\SQL;Initial Catalog=PingMonitorDB;Integrated Security=True");
cnn.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = cnn;
SqlDataAdapter dp = new SqlDataAdapter();
DataTable dtTable = new DataTable();
cmd.CommandText = "SELECT host, ip FROM addhosts";
cmd.CommandType = CommandType.Text;
dp.SelectCommand = cmd;
dp.Fill(dtTable);
cnn.Close();
for (int i = 0; i < dtTable.Rows.Count; i++)
{
ipAddress.Add("ip");
Label lbl = new Label();
lbl.Visible = true;
lbl.AutoSize = true;
lbl.Font = new Font("Arial", 12, FontStyle.Bold);
lbl.Text = dtTable.Rows[i]["host"].ToString() + " " + dtTable.Rows[i]["ip"].ToString();
lbl.BackColor = System.Drawing.Color.Orange;
this.Controls.Add(lbl);
flowLayoutPanel1.Controls.Add(lbl);
var controls = new Control[] { /* a list of existing Controls */ };
// The Addresses count must match the Controls'
var addresses = ["0.0.0.0"]; => Not sure what to do here though?
var massPing = new MassPing();
await massPing.PingAll(addresses, controls, 2000);
}
}
MassPing
Class 显示在上一个问题中:
使用此代码:
SqlConnection cnn = new SqlConnection("....");
cnn.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = cnn;
SqlDataAdapter dp = new SqlDataAdapter();
cmd.CommandText = "SELECT host, ip FROM addhosts";
cmd.CommandType = CommandType.Text;
dp.SelectCommand = cmd;
dp.Fill(dtTable);
cnn.Close();
for (int i = 0; i < dtTable.Rows.Count; i++)
{
Label lbl = new Label();
lbl.Visible = true;
lbl.Text = dtTable.Rows[i]["host"].ToString() + dtTable.Rows[i]["ip"].ToString();
lbl.BackColor = System.Drawing.Color.Orange;
this.Controls.Add(lbl);
}
我已经修改了 MassPing
Class 和 通用化 过程,以不同的方式创建了一个 Progress<T>
委托,在MassPing
class.
SetPingProgressDelegate()
方法在调用 MassPing.PinAll()
方法之前创建委托。
- 在您的代码中,每次读取新记录并以相同方式添加新控件时,您都会调用
PingAll()
方法。
这当然行不通:您需要事先创建一个 IP 地址列表和一个控件列表,然后将创建的控件添加到 FlowLayoutPanel 并将地址列表传递给 MassPing
并等待其结果。
修改数据库访问过程以处理所有创建的一次性对象。
也在等待 SqlClient 提供的 async
方法。
- 将调用代码移至
Shown
事件处理程序(而不是 Load
)。
private async void frmMainWindow_Shown(object sender, EventArgs e)
{
var ipAddresses = new List<string>();
var ipControls = new List<Control>();
var font = new Font("Segoe UI", 20, FontStyle.Regular, GraphicsUnit.Pixel);
string sql = "SELECT [host], [ip] FROM addhosts";
string connString = @"Data Source=PC\SQL;Initial Catalog=PingMonitorDB;Integrated Security=True";
using (var conn = new SqlConnection(connString))
using (var cmd = new SqlCommand(sql, conn)) {
await conn.OpenAsync();
using (var reader = await cmd.ExecuteReaderAsync()) {
int ipCount = 0;
while (await reader.ReadAsync()) {
var lbl = new Label() {
AutoSize = false,
BackColor = Color.LightGray,
ForeColor = Color.Black,
Font = font,
Name = $"lblAddress{ipCount}",
Size = new Size(flowLayoutPanel1.ClientSize.Width, font.Height + 4),
Text = $"{reader["host"]} {reader["ip"]} "
};
ipAddresses.Add(reader["ip"].ToString());
ipControls.Add(lbl);
}
}
}
// If the Reader returned some results, add the Control to a FlowLayoutPanel
// and pass the list of addresses to MassPing, plus the Progress<T> delegate
if (ipAddresses.Count > 0) {
flowLayoutPanel1.Controls.AddRange(ipControls.ToArray());
var massPing = new MassPing();
var progress = SetPingProgressDelegate(ipControls);
await massPing.PingAll(ipAddresses.ToArray(), progress, 2500);
}
}
专业IProgress<T>
委托:
在同一个表单中添加此方法。或者将访问修饰符更改为 public
并将其添加到表单可以到达的 internal
class。
更改颜色以适合您设计的 UI。
private IProgress<(int, object)> SetPingProgressDelegate(List<Control> uiControls)
{
var controls = uiControls;
var obj = new object();
// Create a Progress<T> delegate to receive status updates
// Each Task reports back here. This code is executed in the UI Thread
var progress = new Progress<(int seq, object reply)>(report => {
lock (obj) { // Not strictly necessary. Test without it
var status = IPStatus.Unknown;
var color = Color.LightGray;
if (report.reply is PingReply pr) {
status = pr.Status;
color = status is IPStatus.Success
? pr.RoundtripTime > 10 ? Color.Yellow : Color.LightGreen
: Color.OrangeRed;
}
else if (report.reply is SocketError socErr) {
if (socErr == SocketError.HostNotFound) {
status = IPStatus.DestinationHostUnreachable;
color = Color.Red;
}
else {
// Something else went wrong. Handle if you care.
status = IPStatus.Unknown;
}
}
controls[report.seq].BackColor = color;
controls[report.seq].Text += status.ToString();
}
});
return progress;
}
修改MassPing
class:
接收 IP 地址列表(作为字符串)并初始化相应数量的 PingAsync()
任务。每个 PingAsync()
任务都会报告其结果,包括创建任务时生成的序列指示符。请参阅注释:
using System.Collections.Generic;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Threading.Tasks;
public class MassPing
{
public async Task PingAll(string[] addresses, IProgress<(int seq, object reply)> progress, uint timeout = 2000)
{
var tasks = new List<Task>();
// Add all tasks
for (int seq = 0; seq < addresses.Length; seq++) {
tasks.Add(PingAsync(addresses[seq], (int)timeout, seq, progress));
}
await Task.WhenAll(tasks);
}
private async Task PingAsync(string ipAddress, int timeOut, int sequence, IProgress<(int seq, object reply)> progress)
{
var buffer = new byte[32];
var ping = new Ping();
try {
var options = new PingOptions(64, true);
PingReply reply = await ping.SendPingAsync(ipAddress, timeOut, buffer, options);
progress.Report((sequence, reply));
}
catch (PingException pex) {
if (pex.InnerException is SocketException socEx) {
progress.Report((sequence, socEx.SocketErrorCode));
}
else {
// InnerException should be a SocketException. If not, something went bad
// Handle specific cases if this kind of reporting is needed
progress.Report((sequence, SocketError.SocketError));
}
}
catch (InvalidOperationException) {
// Overlapping sequence. Should never happen
progress.Report((sequence, SocketError.AlreadyInProgress));
}
finally {
ping.Dispose();
}
}
}
我需要在动态创建的标签中显示我的 SQL 数据库中的两个字段。因此,对于数据库中的每个条目,它都需要将其显示在彼此下方标签中的主要 window 上。但它没有显示标签中的信息。
所以这就是需要发生的事情。
用户将信息保存到 SQL 数据库(主机名、IP 地址和设备)
在主屏幕上(windows)然后需要这样显示:
服务器 1 192.168.x.x“Ping 结果”
这是我目前拥有的代码(这还不包括 ping 结果标签)
private void AddDynamicLabels()
{
string ConString = @"Data Source=PC\SQL;Initial Catalog=PingMonitorDB;Integrated Security=True";
SqlConnection con = new SqlConnection(ConString);
string CmdString = "SELECT host, ip FROM addhosts";
SqlCommand cmd = new SqlCommand(CmdString, con);
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
Label lbl = new Label();
lbl.Visible = true;
lbl.Text = reader["host" + "ip" + " "].ToString();
lbl.BackColor = System.Drawing.Color.Orange;
this.Controls.Add(lbl);
}
con.Close();
}
因此,对于添加的每个条目,理论上应该如下所示:
Server 1 192.168.x.x "ping reply"
Server 2 192.168.x.x "ping reply"
Server 3 192.168.x.x "ping reply"
....
etc
编辑
private async void frmMainWindow_Load(object sender, EventArgs e)
{
SqlConnection cnn = new SqlConnection(@"Data Source=PC\SQL;Initial Catalog=PingMonitorDB;Integrated Security=True");
cnn.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = cnn;
SqlDataAdapter dp = new SqlDataAdapter();
DataTable dtTable = new DataTable();
cmd.CommandText = "SELECT host, ip FROM addhosts";
cmd.CommandType = CommandType.Text;
dp.SelectCommand = cmd;
dp.Fill(dtTable);
cnn.Close();
for (int i = 0; i < dtTable.Rows.Count; i++)
{
ipAddress.Add("ip");
Label lbl = new Label();
lbl.Visible = true;
lbl.AutoSize = true;
lbl.Font = new Font("Arial", 12, FontStyle.Bold);
lbl.Text = dtTable.Rows[i]["host"].ToString() + " " + dtTable.Rows[i]["ip"].ToString();
lbl.BackColor = System.Drawing.Color.Orange;
this.Controls.Add(lbl);
flowLayoutPanel1.Controls.Add(lbl);
var controls = new Control[] { /* a list of existing Controls */ };
// The Addresses count must match the Controls'
var addresses = ["0.0.0.0"]; => Not sure what to do here though?
var massPing = new MassPing();
await massPing.PingAll(addresses, controls, 2000);
}
}
MassPing
Class 显示在上一个问题中:
使用此代码:
SqlConnection cnn = new SqlConnection("....");
cnn.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = cnn;
SqlDataAdapter dp = new SqlDataAdapter();
cmd.CommandText = "SELECT host, ip FROM addhosts";
cmd.CommandType = CommandType.Text;
dp.SelectCommand = cmd;
dp.Fill(dtTable);
cnn.Close();
for (int i = 0; i < dtTable.Rows.Count; i++)
{
Label lbl = new Label();
lbl.Visible = true;
lbl.Text = dtTable.Rows[i]["host"].ToString() + dtTable.Rows[i]["ip"].ToString();
lbl.BackColor = System.Drawing.Color.Orange;
this.Controls.Add(lbl);
}
我已经修改了 MassPing
Class 和 通用化 过程,以不同的方式创建了一个 Progress<T>
委托,在MassPing
class.
SetPingProgressDelegate()
方法在调用 MassPing.PinAll()
方法之前创建委托。
- 在您的代码中,每次读取新记录并以相同方式添加新控件时,您都会调用
PingAll()
方法。
这当然行不通:您需要事先创建一个 IP 地址列表和一个控件列表,然后将创建的控件添加到 FlowLayoutPanel 并将地址列表传递给MassPing
并等待其结果。
修改数据库访问过程以处理所有创建的一次性对象。
也在等待 SqlClient 提供的 async
方法。
- 将调用代码移至
Shown
事件处理程序(而不是Load
)。
private async void frmMainWindow_Shown(object sender, EventArgs e)
{
var ipAddresses = new List<string>();
var ipControls = new List<Control>();
var font = new Font("Segoe UI", 20, FontStyle.Regular, GraphicsUnit.Pixel);
string sql = "SELECT [host], [ip] FROM addhosts";
string connString = @"Data Source=PC\SQL;Initial Catalog=PingMonitorDB;Integrated Security=True";
using (var conn = new SqlConnection(connString))
using (var cmd = new SqlCommand(sql, conn)) {
await conn.OpenAsync();
using (var reader = await cmd.ExecuteReaderAsync()) {
int ipCount = 0;
while (await reader.ReadAsync()) {
var lbl = new Label() {
AutoSize = false,
BackColor = Color.LightGray,
ForeColor = Color.Black,
Font = font,
Name = $"lblAddress{ipCount}",
Size = new Size(flowLayoutPanel1.ClientSize.Width, font.Height + 4),
Text = $"{reader["host"]} {reader["ip"]} "
};
ipAddresses.Add(reader["ip"].ToString());
ipControls.Add(lbl);
}
}
}
// If the Reader returned some results, add the Control to a FlowLayoutPanel
// and pass the list of addresses to MassPing, plus the Progress<T> delegate
if (ipAddresses.Count > 0) {
flowLayoutPanel1.Controls.AddRange(ipControls.ToArray());
var massPing = new MassPing();
var progress = SetPingProgressDelegate(ipControls);
await massPing.PingAll(ipAddresses.ToArray(), progress, 2500);
}
}
专业IProgress<T>
委托:
在同一个表单中添加此方法。或者将访问修饰符更改为 public
并将其添加到表单可以到达的 internal
class。
更改颜色以适合您设计的 UI。
private IProgress<(int, object)> SetPingProgressDelegate(List<Control> uiControls)
{
var controls = uiControls;
var obj = new object();
// Create a Progress<T> delegate to receive status updates
// Each Task reports back here. This code is executed in the UI Thread
var progress = new Progress<(int seq, object reply)>(report => {
lock (obj) { // Not strictly necessary. Test without it
var status = IPStatus.Unknown;
var color = Color.LightGray;
if (report.reply is PingReply pr) {
status = pr.Status;
color = status is IPStatus.Success
? pr.RoundtripTime > 10 ? Color.Yellow : Color.LightGreen
: Color.OrangeRed;
}
else if (report.reply is SocketError socErr) {
if (socErr == SocketError.HostNotFound) {
status = IPStatus.DestinationHostUnreachable;
color = Color.Red;
}
else {
// Something else went wrong. Handle if you care.
status = IPStatus.Unknown;
}
}
controls[report.seq].BackColor = color;
controls[report.seq].Text += status.ToString();
}
});
return progress;
}
修改MassPing
class:
接收 IP 地址列表(作为字符串)并初始化相应数量的 PingAsync()
任务。每个 PingAsync()
任务都会报告其结果,包括创建任务时生成的序列指示符。请参阅注释:
using System.Collections.Generic;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Threading.Tasks;
public class MassPing
{
public async Task PingAll(string[] addresses, IProgress<(int seq, object reply)> progress, uint timeout = 2000)
{
var tasks = new List<Task>();
// Add all tasks
for (int seq = 0; seq < addresses.Length; seq++) {
tasks.Add(PingAsync(addresses[seq], (int)timeout, seq, progress));
}
await Task.WhenAll(tasks);
}
private async Task PingAsync(string ipAddress, int timeOut, int sequence, IProgress<(int seq, object reply)> progress)
{
var buffer = new byte[32];
var ping = new Ping();
try {
var options = new PingOptions(64, true);
PingReply reply = await ping.SendPingAsync(ipAddress, timeOut, buffer, options);
progress.Report((sequence, reply));
}
catch (PingException pex) {
if (pex.InnerException is SocketException socEx) {
progress.Report((sequence, socEx.SocketErrorCode));
}
else {
// InnerException should be a SocketException. If not, something went bad
// Handle specific cases if this kind of reporting is needed
progress.Report((sequence, SocketError.SocketError));
}
}
catch (InvalidOperationException) {
// Overlapping sequence. Should never happen
progress.Report((sequence, SocketError.AlreadyInProgress));
}
finally {
ping.Dispose();
}
}
}