TableLayoutPanel 更新滞后
TableLayoutPanel update lag
我有一个 WinForms 应用程序正在从 BackgroundWorker 更新 TableLayoutPanel。根据设备输入是打开 (1) 还是关闭 (0),颜色和某些文本会相应更改。
try
{
//Define a new TLP to hold the search tablelayoutpanel.
//search for the iterated card number.
//get the status label using GetControl from Position.
TableLayoutPanel TLP = new TableLayoutPanel();
string IO_Card_Name = "ED527_" + i.ToString();
TLP = TLP_IO_Info.Controls.Find(IO_Card_Name, true).FirstOrDefault() as TableLayoutPanel;
try { lbl = TLP.GetControlFromPosition(4, 0) as Label; } catch { lbl = null; };
//if card is found (because input is active, colour the TLP (card) according to its state.
if (TLP != null && lbl != null && INPUTS[i - 1] == 1)
{
TLP.BackColor = Color.Green;
foreach (Label l in TLP.Controls)
{
l.BackColor = Color.Green;
}
lbl.Invoke((MethodInvoker)delegate { lbl.Text = "ON"; });
}
else if (TLP != null && lbl != null && INPUTS[i - 1] == 0)
{
TLP.BackColor = Color.White;
foreach (Label l in TLP.Controls)
{
l.BackColor = Color.White;
}
lbl.Invoke((MethodInvoker)delegate { lbl.Text = "OFF"; });
}
}
catch (Exception exception)
{
MessageBox.Show(exception.Message);
};
TLP
包含 5 个标签。当线路更新时,更新显示出一些明显的滞后。有没有一种方法可以在 UI 主线程上执行类似于 SuspendLayout()
/ ResumeLayout
的操作?
****编辑以显示之前和之后 - IOLabel 列在 Status 列之前稍微更新。
听起来你有一个嵌套设计。每行 5 个标签由不同的 TableLayoutPanel 托管,TLP_IO_Info
是一个 TableLayoutPanel 托管其他 TableLayoutPanel。在 BackgroundWorker 的 DoWork
事件中,您有一个 for..loop
可以根据设备的当前 状态 更改内部控件的 Backcolor
您从 INPUT
int 数组中读取它。请指正。
我想推荐这个:
foreach (var tlp in TLP_IO_Info.Controls.OfType<TableLayoutPanel>()
.Where(x => x.Name.StartsWith("ED527_")))
{
if (tlp.GetControlFromPosition(4, 0) is Label lbl)
{
var state = // get the state of the current device from INPUT array
var stateColor = state == 1 ? Color.Green : Color.White;
var stateText = state == 1 ? "ON" : "OFF";
this.Invoke(new Action(() =>
{
tlp.BackColor = stateColor;
tlp.Controls.OfType<Label>().ToList().ForEach(l => l.BackColor = stateColor);
lbl.Text = stateText;
}));
}
}
或者这样来消除冗余代码:
var stateColors = new[] { Color.White, Color.Green };
var stateTexts = new[] { "OFF", "ON" };
foreach (var tlp in TLP_IO_Info.Controls.OfType<TableLayoutPanel>()
.Where(x => x.Name.StartsWith("ED527_")))
{
if (tlp.GetControlFromPosition(4, 0) is Label lbl)
{
var state = // get the state of the current device from INPUT array
this.Invoke(new Action(() =>
{
tlp.BackColor = stateColors[state];
tlp.Controls.OfType<Label>().ToList()
.ForEach(l => l.BackColor = stateColors[state]);
lbl.Text = stateTexts[state];
}));
}
}
请注意,我删除了昂贵的 try..catch
块,因为此代码不会引发任何异常。
至于 INPUT
数组,我建议您将其替换为 Dictionary<string, int>
以存储每个设备的当前状态(根据您提供的 link ) 每个设备都有一个唯一的 IOLineNumber
,因此您可以轻松 set/get 每个设备的当前状态。
⍰也许图书馆里已经有这样的东西了?
我有一个 WinForms 应用程序正在从 BackgroundWorker 更新 TableLayoutPanel。根据设备输入是打开 (1) 还是关闭 (0),颜色和某些文本会相应更改。
try
{
//Define a new TLP to hold the search tablelayoutpanel.
//search for the iterated card number.
//get the status label using GetControl from Position.
TableLayoutPanel TLP = new TableLayoutPanel();
string IO_Card_Name = "ED527_" + i.ToString();
TLP = TLP_IO_Info.Controls.Find(IO_Card_Name, true).FirstOrDefault() as TableLayoutPanel;
try { lbl = TLP.GetControlFromPosition(4, 0) as Label; } catch { lbl = null; };
//if card is found (because input is active, colour the TLP (card) according to its state.
if (TLP != null && lbl != null && INPUTS[i - 1] == 1)
{
TLP.BackColor = Color.Green;
foreach (Label l in TLP.Controls)
{
l.BackColor = Color.Green;
}
lbl.Invoke((MethodInvoker)delegate { lbl.Text = "ON"; });
}
else if (TLP != null && lbl != null && INPUTS[i - 1] == 0)
{
TLP.BackColor = Color.White;
foreach (Label l in TLP.Controls)
{
l.BackColor = Color.White;
}
lbl.Invoke((MethodInvoker)delegate { lbl.Text = "OFF"; });
}
}
catch (Exception exception)
{
MessageBox.Show(exception.Message);
};
TLP
包含 5 个标签。当线路更新时,更新显示出一些明显的滞后。有没有一种方法可以在 UI 主线程上执行类似于 SuspendLayout()
/ ResumeLayout
的操作?
****编辑以显示之前和之后 - IOLabel 列在 Status 列之前稍微更新。
听起来你有一个嵌套设计。每行 5 个标签由不同的 TableLayoutPanel 托管,TLP_IO_Info
是一个 TableLayoutPanel 托管其他 TableLayoutPanel。在 BackgroundWorker 的 DoWork
事件中,您有一个 for..loop
可以根据设备的当前 状态 更改内部控件的 Backcolor
您从 INPUT
int 数组中读取它。请指正。
我想推荐这个:
foreach (var tlp in TLP_IO_Info.Controls.OfType<TableLayoutPanel>()
.Where(x => x.Name.StartsWith("ED527_")))
{
if (tlp.GetControlFromPosition(4, 0) is Label lbl)
{
var state = // get the state of the current device from INPUT array
var stateColor = state == 1 ? Color.Green : Color.White;
var stateText = state == 1 ? "ON" : "OFF";
this.Invoke(new Action(() =>
{
tlp.BackColor = stateColor;
tlp.Controls.OfType<Label>().ToList().ForEach(l => l.BackColor = stateColor);
lbl.Text = stateText;
}));
}
}
或者这样来消除冗余代码:
var stateColors = new[] { Color.White, Color.Green };
var stateTexts = new[] { "OFF", "ON" };
foreach (var tlp in TLP_IO_Info.Controls.OfType<TableLayoutPanel>()
.Where(x => x.Name.StartsWith("ED527_")))
{
if (tlp.GetControlFromPosition(4, 0) is Label lbl)
{
var state = // get the state of the current device from INPUT array
this.Invoke(new Action(() =>
{
tlp.BackColor = stateColors[state];
tlp.Controls.OfType<Label>().ToList()
.ForEach(l => l.BackColor = stateColors[state]);
lbl.Text = stateTexts[state];
}));
}
}
请注意,我删除了昂贵的 try..catch
块,因为此代码不会引发任何异常。
至于 INPUT
数组,我建议您将其替换为 Dictionary<string, int>
以存储每个设备的当前状态(根据您提供的 link ) 每个设备都有一个唯一的 IOLineNumber
,因此您可以轻松 set/get 每个设备的当前状态。
⍰也许图书馆里已经有这样的东西了?