Выделите определенные символы во всех ячейках DataGridView

Когда я выполняю поиск символов в DataGridView, я хочу, чтобы были выбраны только искомые определенные символы (я выделяю их красным полем), не выбирая все символы в ячейке. Как мне это сделать?

Я написал код, и результат выглядит так:

Ожидаемый результат:

Я хочу, чтобы был выбран только искомый конкретный символ (я даю ему красную рамку), не выбирая все символы в ячейке

private void AddCustomer_DataGridView_CellFormatting(object? sender, DataGridViewCellFormattingEventArgs e)
{
    try
    {
        if (e.RowIndex >= 0 && e.ColumnIndex >= 0)
        {
            if (!String.IsNullOrEmpty(AddCustomer_SearchTextBox.Text) && e.Value != null)
            {
                string strValue = (String)e.Value;
                if (strValue.Contains(AddCustomer_SearchTextBox.Text))
                {
                    DataGridViewCellStyle? cellStyle = e.CellStyle;
                    if (cellStyle != null)
                    {
                        // Problem ini here, how to select only specific characters in a cell (not all characters)
                        cellStyle.BackColor = ColorTranslator.FromHtml("#0078D7");
                        cellStyle.ForeColor = ColorTranslator.FromHtml("#FFFFFF");
                    }
                }
            }
        }
    }
    catch (Exception ex)
    {
        ExLogger.LogException(ex, "");
        MessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}

// Работает нормально

public List<Customer>? SearchCustomers(int count, int minOffset, int maxOffset, string keyword, string sortExpression = "ASC")
{
    if (count <= 0)
    {
        return new List<Customer>();
    }

    int limit = 1 + (maxOffset - minOffset);
    if (limit < 0)
    {
        limit = 0;
    }

    int offset = minOffset - 1; // start
    if (offset < 0)
    {
        offset = 0;
    }
    if (offset >= count)
    {
        offset = count - 1;
    }

    string sql = @"SELECT customer.ID, customer.created, customer.name, customer.place_of_birth, customer.date_of_birth, customer.gender_id, customer.address, customer.neighbourhood_hamlet, customer.urban_village, customer.subdistrict, customer.religion_id, customer.marital_status_id, customer.profession, customer.citizenship_id, customer.email, customer.phone_number, customer.send_me 
                    FROM customer 
                        INNER JOIN gender ON gender_id = gender.ID 
                        INNER JOIN religion ON religion_id = religion.ID 
                        INNER JOIN marital_status ON marital_status_id = marital_status.ID 
                        INNER JOIN citizenship ON citizenship_id = citizenship.ID 
                    WHERE customer.ID LIKE @ID OR 
                          customer.created LIKE @created OR 
                          customer.name LIKE @name OR 
                          customer.place_of_birth LIKE @place_of_birth OR 
                          customer.date_of_birth LIKE @date_of_birth OR 
                          gender.gender_name LIKE @gender_id OR 
                          customer.address LIKE @address OR 
                          customer.neighbourhood_hamlet LIKE @neighbourhood_hamlet OR 
                          customer.urban_village LIKE @urban_village OR 
                          customer.subdistrict LIKE @subdistrict OR 
                          religion.religion_name LIKE @religion_id OR 
                          marital_status.marital_name LIKE @marital_status_id OR 
                          customer.profession LIKE @profession OR 
                          citizenship.citizenship_name LIKE @citizenship_id OR 
                          customer.email LIKE @email OR 
                          customer.phone_number LIKE @phone_number OR 
                          customer.send_me LIKE @send_me 
                    ORDER BY STR_TO_DATE(customer.created, '%d/%m/%Y %H:%i:%s') " + sortExpression + " LIMIT " + limit + " OFFSET " + offset;

    object[] parms = { "@ID",  '%'+ keyword + '%',
                       "@created",  '%'+ keyword + '%',
                       "@name",  '%'+ keyword + '%',
                       "@place_of_birth",  '%'+ keyword + '%',
                       "@date_of_birth",  '%'+ keyword + '%',
                       "@gender_id",  '%'+ keyword + '%',
                       "@address",  '%'+ keyword + '%',
                       "@neighbourhood_hamlet",  '%'+ keyword + '%',
                       "@urban_village",  '%'+ keyword + '%',
                       "@subdistrict",  '%'+ keyword + '%',
                       "@religion_id",  '%'+ keyword + '%',
                       "@marital_status_id",  '%'+ keyword + '%',
                       "@profession",  '%'+ keyword + '%',
                       "@citizenship_id",  '%'+ keyword + '%',
                       "@email",  '%'+ keyword + '%',
                       "@phone_number",  '%'+ keyword + '%',
                       "@send_me",  '%'+ keyword + '%'
                     };

    return db.Read(sql, Make, parms).ToList();
}

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
81
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете обработать событие CellPainting, чтобы выделить фрагменты текста внутри ячеек DataGridView.
Метод StringFormat.SetMeasurableCharacterRanges() можно использовать для создания элементов CharacterRange , которые затем передаются в Graphics.MeasureCharacterRanges() для создания регионов, описывающих границы разделов текста в этих диапазонах.

Некоторые вещи, которые следует иметь в виду:

  1. Вам нужно вызвать e.PaintBackground() и e.PaintContent(), чтобы сбросить рендеринг ячеек, когда их нужно обновить, иначе вы в конечном итоге будете рисовать одну и ту же графику несколько раз на одной и той же графической поверхности.
  2. Вам нужно установить e.Handled = true, когда вы рисуете свой собственный графический контент, иначе он не будет отображаться.
  3. Необходимо учитывать выравнивание текста в ячейках. Обычно центрируется по вертикали, но также может быть по центру по горизонтали или как-то еще (например, выровнено по левому/верхнему краю). Поскольку это находится под нашим контролем, мы можем соответствующим образом настроить вертикальное и горизонтальное выравнивание StringFormat. В примере я принимаю раскладку по умолчанию и указываю [StringFormat].LineAlignment = StringAlignment.Center;
  4. Текст одной или нескольких ячеек может содержать строку поиска несколько раз, поэтому лучше использовать простое регулярное выражение, чтобы найти все совпадающие разделы текста, чтобы мы могли выделить все
  5. Вы можете заполнить содержимое региона, но если вместо этого вам нужен прямоугольник, поскольку некоторые методы рисования не принимают регион в качестве области рисования, вы можете преобразовать регион в RectangleF с помощью [Region].GetBounds([Graphics]). Используйте Rectangle.Round(), чтобы создать Rectangle
  6. Всегда используйте значение e.CellBounds для определения границ текста, который вы отправляете методам, используемым как для измерения текста, так и для рендеринга графики; если вы обнаружите, что корректируете эти границы с помощью магических чисел, в процедуре что-то не так. Если вам нужно переместить регион, используйте [Region].Translate(); чтобы переместить прямоугольник, используйте [Rectangle].Offset() или [Rectangle].Inflate()
  7. Вам нужно избавиться от всех одноразовых предметов. Это включает (здесь) StringFormat и кисти/перья, которые вы создаете, если только вы не используете стандартные объекты, которые вы получаете из классов Brushes, Pens и SystemBrushes. Явное удаление этих объектов очень важно, они содержат неуправляемые ресурсы. ГК вам не поможет

private void someDataGridView_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
    if (e.ColumnIndex < 0 || e.RowIndex < 0) return;
    e.PaintBackground(e.ClipBounds, true);
    e.PaintContent(e.ClipBounds);

    var cellValue = e.FormattedValue?.ToString();
    if (string.IsNullOrEmpty(searchString) || string.IsNullOrEmpty(cellValue)) return;

    var positions = Regex.Matches(cellValue, searchString);
    if (positions.Count == 0) return;

    using (var format = new StringFormat(StringFormatFlags.FitBlackBox)) {
        // The Cell's vertical alignment is usually centered. Adjust as required
        format.LineAlignment = StringAlignment.Center;
        // Generates ranges for all matching strings found 
        format.SetMeasurableCharacterRanges(positions.OfType<Match>()
              .Select(m => new CharacterRange(m.Index, m.Length)).ToArray());
        // Generate Regions that contain the search text
        var regions = e.Graphics.MeasureCharacterRanges(cellValue, e.CellStyle.Font, e.CellBounds, format);

        using (var brush = new SolidBrush(Color.FromArgb(80, Color.Fuchsia))) {
            foreach (var region in regions) {
                e.Graphics.FillRegion(brush, region);
                // And / or draw a rectangle around the claculated box
                e.Graphics.DrawRectangle(Pens.Red, Rectangle.Round(region.GetBounds(e.Graphics)));
            }
        }
    }
    e.Handled = true;
}

Вы можете подписаться на событие KeyDown TextBox для обработки ключа Enter и аннулирования вашего DataGridView при изменении строки поиска:

private string searchString = "";

private void searchTextBox_KeyDown(object sender, KeyEventArgs e) {
    if (e.KeyCode == Keys.Enter) {
        e.SuppressKeyPress = true;
        searchString = (sender as Control).Text;
        someDataGridView.Invalidate();
    }
}

Вот как это работает:

@ Джими Спасибо, брат, за объяснение. Теперь я это понимаю.

Ihdina 07.06.2023 04:32

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

Jimi 07.06.2023 05:11

Другие вопросы по теме