Запаздывание обновления TableLayoutPanel - PullRequest
2 голосов
/ 21 апреля 2020

У меня есть приложение WinForms, которое обновляет TableLayoutPanel из BackgroundWorker. В зависимости от того, включен ли ввод устройства (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 ярлыков. Обновление показывает некоторое заметное отставание при обновлении линии. Есть ли способ сделать что-то похожее на SuspendLayout() / ResumeLayout в основном потоке пользовательского интерфейса?

**** РЕДАКТИРОВАТЬ, чтобы показать до и после - столбец IOLabel немного обновляется перед столбцом состояния.

Table Layout Panel

1 Ответ

2 голосов
/ 22 апреля 2020

Похоже, у вас есть вложенный дизайн. В каждой строке по 5 меток размещаются разные TableLayoutPanels, а TLP_IO_Info, который является TableLayoutPanel, размещает другие TableLayoutPanels. В событии DoWork BackgroundWorker у вас есть 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> для хранения текущего состояния каждого устройства. поскольку (согласно предоставленной вами ссылке) каждое устройство имеет уникальный IOLineNumber, поэтому вы можете легко установить / получить текущее состояние каждого из них.

⍰ Возможно, что-то подобное уже есть в библиотеке?

...