Событие DrawItem вызывается слишком много раз при добавлении элементов - PullRequest
0 голосов
/ 04 ноября 2011

В моем приложении WinForms у меня есть таймер, который «тикает» каждую секунду. В тик-методе этого таймера я делаю разные вещи, включая добавление элементов в список (называемый lbxLogText).

Мне нужно иметь возможность раскрасить текст некоторых элементов (цвет определяется до добавления элемента). Из-за этого я установил для свойства DrawMode значение OwnerDrawVariable, а метод lbxLogText_DrawItem выглядит следующим образом:

private void lbxLogText_DrawItem(object sender, DrawItemEventArgs e)
{
    e.DrawBackground();
    e.DrawFocusRectangle();
    e.Graphics.DrawString(logStringToAdd, 
        new Font(FontFamily.GenericSansSerif, 8),
        new SolidBrush(logStringToAddColor), e.Bounds);

    testCounter++;
    label29.Text = testCounter.ToString();
}

logStringToAdd: глобальный string.

logStringToAddColor: глобальный Color - красный или черный.

testCounter: глобальный int, инициированный до 0.

У меня есть метод с именем Log(). Это вызывается в тик-методе таймера, упомянутого выше.

Вот как это выглядит:

private void Log(string status)
{
    // |red, |black
    if (status != null)
    {
        if (status.Contains("|red"))
        {
            status = status.Replace("|red", "");
            logStringToAddColor = Color.Red;
        }
        else if (status.Contains("|black"))
        {
            status = status.Replace("|black", "");
            logStringToAddColor = Color.Black;
        }
        logStringToAdd = status;
        lbxLogText.Items.Add(new object());
    }

    // scroll to bottom
    lbxLogText.SetSelected(lbxLogText.Items.Count - 1, true);
    lbxLogText.SetSelected(lbxLogText.Items.Count - 1, false);
}

status: Может быть «Система работает правильно. | Черный» или «Система НЕ работает правильно. | Красный» (например). Этот параметр обновляется перед лог-вызовом (конечно).

Этот код работает в некоторой степени нормально. У меня есть следующие проблемы:

  • при запуске программы на label29 я вижу, что переменная testCounter не просто увеличивается каждую секунду, она начинается с 1, затем становится 3, затем 6, 10, 15, 21 , 28, 36 (я думаю, что вы получили образец сейчас). Это означает, что событие DrawItem вызывается на больше , чем просто каждую секунду.

  • скажем, status переходит от "asd123 | black" к "qwe456 | red". Это означает, что следующий элемент, добавленный в список, должен быть красным. Что ж, он становится красным, но все элементов в списке становятся красными. И текст всех предметов также изменен на самый новый.

  • при отладке я вижу, что при вызове метода SetSelected он переходит прямо к методу события DrawItem. Но я не понимаю, как этого избежать, так как мне нужно, чтобы при добавлении нового элемента список прокручивался вниз, чтобы был виден новый элемент.

Ответы [ 2 ]

4 голосов
/ 04 ноября 2011

DrawItem вызывается не один раз при добавлении нового элемента, а вызывается для каждого элемента , уже присутствующего в ListBox.Вот почему в вашем случае он вызывается чаще, чем раз в секунду.

Это также объясняет шаблон label29 ( "1, затем становится 3, затем 6, 10, 15, 21, 28,36 "), поскольку все элементы перерисовываются при каждом добавлении нового элемента.

И, конечно, поскольку вы используете глобальную переменную для установки цвета элемента, каждый элемент перерисовывается с помощьюзначение этой переменной - объяснение, почему все ваши предметы становятся красными.

1 голос
/ 04 ноября 2011

Как сказал Отиель, DrawItem вызывается всякий раз, когда требуется перерисовать любой элемент, и вы используете глобальное состояние для хранения текста и цвета для всех элементов.

Чтобы сделать его специфичным для каждого элемента.item, вы можете добавить экземпляр объекта / типа, который возвращает текст как .ToString (), но вы можете запросить цвет в вашем событии DrawItem:

struct LogItem {
  public string Text;
  public Colour ItemColour
}

private void Log(string status) { 
  LogItem item = new LogItem();
  item.Text = "Wibble";
  item.ItemColour = Colours.Red;
  lbxLogText.Items.Add(item); 
}

private void lbxLogText_DrawItem(object sender, DrawItemEventArgs e) {   
  LogItem item = lbxLogText.Items[e.Index];
  e.DrawBackground();   
  e.DrawFocusRectangle();   
  e.Graphics.DrawString(item.Text,    
    new Font(FontFamily.GenericSansSerif, 8),   
    new SolidBrush(item.Color), e.Bounds);   
}  
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...