Почему я получаю разные результаты при запуске одного и того же кода в событии TextChanged в отличие от нажатия кнопки? - PullRequest
2 голосов
/ 01 июля 2019

У меня есть функция, которая просматривает Datagridview и находит любые совпадения с предоставленным поисковым запросом. Он использует "попадания", которые он находит, чтобы нарисовать панель справа от сетки данных, показывающую, где совпадения относятся к полосе прокрутки.

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

Это происходит только при первом запуске кода за сеанс отладки. В остальной части сеанса событие изменения текста работает нормально, и на панели остаются окрашенные разделы, как и должно быть.

Первоначально для целей разработки у меня был код непосредственно внутри обработчика событий кнопки. Только когда я поместил тот же код в событие изменения текста, я впервые увидел проблему.

С тех пор я поместил код в его собственную функцию, вызывая его как при нажатии кнопки, так и при изменении текста.

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

private void btnSearch_Click(object sender, EventArgs e)
{
    Search();
}

private void TbSearch_TextChanged(object sender, EventArgs e)
{
    Search();
}

«Поиск» содержит:

private void Search()
{
    PanelClear();
    if (tbSearch.Text.Length > 2)
    {
       Searchy(tbSearch.Text);

        if (_hits.Count > 0)
        {
            foreach (var hit in _hits){PanelPaint_paint(hit);}
        }
    }
}

PanelClear содержит:

private void PanelClear()
{
    //Clears the list of matches.
    _hits.Clear();
    //Invalidates my panel control. 
    panelPaint.Invalidate();
    //Hides a textbox
    tbTotal.Visible = false;
}

А PanelPaint_paint:

private void PanelPaint_paint(Hit hit)
{
    Graphics g = panelPaint.CreateGraphics();
    Color xx = ext.myColor;
    Color saved = hit.color;
    if (saved != Color.Empty) xx = hit.color;
    Pen myPen = new Pen(xx) { Width = 1 };
    int dgvl = dgvEvents.Rows.Count;
    int pnll = panelPaint.Height;
    int hitl = hit.RowNum;
    double percent = ((double)hitl / (double)dgvl) * pnll;
    float x = (float)percent;
    g.DrawLine(myPen, 1, x, panelPaint.Width, x);
    dgvEvents.Rows[hit.RowNum].Cells[2].Style = new DataGridViewCellStyle
    {
        BackColor = xx,
        ForeColor = invert(xx)
    };
    extrabuttons(true);
    tbTotal.Text = allhits().Count.ToString();
}

Итак, вот рисунок, показывающий, что происходит, когда я запускаю поиск простым нажатием кнопки:
Панель Paint on Button Click событие

Вы заметите, я нажимаю кнопку, и панель сохраняет свою краску.

Вот что произойдет, если я помещу этот же код в обработчик событий TextChanged:
Панель Paint на событии TextChanged

Он не выполняет поиск, пока не наберет 3 символа, поэтому вы увидите, как только я введу «U», он запустит поиск, раскрасит панель, но затем сразу очистит ее. Все другие поиски, например, когда я добавляю «E» или возвращаем назад на «U», работают нормально.

1 Ответ

2 голосов
/ 02 июля 2019

Когда вы создаете объект Graphics следующим образом:

Graphics g = panelPaint.CreateGraphics();

то, что вы рисуете с использованием этого объекта, не будет сохраняться.Элемент управления генерирует новый объект Graphics каждый раз, когда он перерисовывается (становится недействительным).Это случается часто.Это означает, что чертеж необходимо обновлять каждый раз, когда элемент управления становится недействительным, используя текущий объект Graphics, предоставленный событием *1005* PaintEventArgs события Paint.(Вы часто найдете эту рекомендацию в Документах MSDN и во многих вопросах в StackOverflow).

По этой причине вы всегда выполняете всю рисование в обработчике Paint (или переопределенном OnPaint метод).

Различные события могут привести к тому, что элемент управления будет признан недействительным (перекрашен): когда форма свернута / развернута, когда другой объект / окно перемещается поверх него, когда система передает сообщение об изменении настроек (и другие).) и многие другие условия.

Также, когда функция Forms AutoValidate вызывает ее:

Получает или задает значение, указывающее, будут ли элементы управления в этом контейнере автоматически проверяться при изменении фокуса.

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

private void Search() {
    _hits.Clear();
    tbTotal.Visible = false;
    if (tbSearch.Text.Length < 3) return;
    Searchy(tbSearch.Text);
    if (_hits.Count == 0) return;

    foreach (var hit in _hits) {
        dgvEvents.Rows[hit.RowNum].Cells[2].Style = new DataGridViewCellStyle {
            BackColor = hit.color == Color.Empty ? ext.myColor : hit.color,
            ForeColor = invert(BackColor)
        };
    }
    panelPaint.Invalidate();
    extrabuttons(true);
    tbTotal.Text = allhits().Count.ToString();
}

private void panelPaint_Paint(object sender, PaintEventArgs e)
{
    if (_hits.Count == 0) return;
    e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
    foreach (var hit in _hits) {
        PaintPanel(hit, e.Graphics);
    }
}

private void PaintPanel(Hit hit, Graphics g)
{
    using (Pen myPen = new Pen(hit.color == Color.Empty ? ext.myColor : hit.color, 1)) {
        float percent = ((float)hit.RowNum / dgvEvents.Rows.Count) * (float)panelPaint.Height;
        g.DrawLine(myPen, 1, percent, panelPaint.Width, percent);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...