【问题标题】:TableLayoutPanel update lagTableLayoutPanel 更新滞后
【发布时间】:2020-04-21 19:25:09
【问题描述】:

我有一个 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 的操作?

****EDIT 显示之前和之后 - IOLabel 列在 Status 列之前稍稍更新。

【问题讨论】:

  • 我确定你不是这个意思TableLayoutPanel TLP = new TableLayoutPanel();除其他外。,,,,
  • 为什么在 Invoke 方法中设置文本,但在没有 Invoke 的情况下设置颜色?我认为对 GUI 的所有更改都必须在 Invoke 中。所有这些代码仅更改标签,将其全部放在一个 Invoke 中(它将在主线程中调用)。填充 INPUTS 的 BackgroundWorker 函数的另一部分让工作在自己的线程中。如果扫描设备非常频繁,则取消更新 UI 可能会出现时间延迟。将小 Thread.Sleep() 放在一个扫描循环之后或在计时器中扫描。
  • @JQSOFT 我先说一下我没有接受过作为计算机科学家的正式培训的事实,所以我确信我的代码中有许多失礼。
  • @AlexeyObukhov - 我确实这么认为,但由于某种原因它不会抛出带有颜色的异常......我会将它全部弹出到调用中。此代码块是从具有Thread.Sleep(100) 暂停的后台工作人员调用的。
  • 对不起哥们,只是想传递一个提示进行检查。犯错是工作的重要组成部分。没有错误/错误/异常意味着您不会编写太多代码。现在,如果您请详细说明一下以澄清诸如Device 开/关部分是什么意思?什么是INPUTS 数组?以便我们更好地理解问题。

标签: c# backgroundworker tablelayoutpanel


【解决方案1】:

听起来你有一个嵌套设计。每行是 5 个标签,由不同的 TableLayoutPanel 托管,TLP_IO_Info 是 TableLayoutPanel 托管其他 TableLayoutPanel。在 BackgroundWorker 的 DoWork 事件中,您有一个 for..loop 以根据您从 INPUT int 读取的设备的当前 state 更改内部控件的 Backcolor大批。请纠正我。

我想建议这个:

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&lt;string, int&gt; 以存储每个设备的当前状态,因为(根据您提供的链接)每个设备都有一个唯一的IOLineNumber 所以您可以轻松设置/获取每个的当前状态。

⍰也许图书馆里已经有类似的东西了?

【讨论】:

  • 谢谢你!这使得更新更加顺畅。我必须稍微修改它以适应(还有一个OUTPUTS 数组),但这真的很优雅,并且给了我一些有趣的语法来研究。我从来没有使用过这样的语法:var stateColor = state == 1 ? Color.Green : Color.White;,再次感谢! :)
  • 如果我可以问一个额外的问题,我还试图让tlp 的颜色由用户定义。即var stateColor = state == 1 ? Color.**User Defined Colour** : Color.White; 我怎样才能将此信息灌输到我的tlplbl
  • 欢迎好友,谢谢。至于颜色问题,您需要以某种方式将该颜色存储在您的应用程序中,以便随时随地设置/获取它。使用application settings,添加Color类型的新设置条目,如MyColor,然后你可以像Properties.Settings.Default.MyColor一样访问它来设置/获取它。在我们的 sn-p 中使用它:var stateColor = state == 1 ? Properties.Settings.Default.MyColor : Color.White;
猜你喜欢
  • 1970-01-01
  • 2018-10-18
  • 1970-01-01
  • 2012-06-02
  • 2014-08-21
  • 2016-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多