winforms 突出显示DataGridView单元格中的搜索结果

7fhtutme  于 2022-11-17  发布在  其他
关注(0)|答案(1)|浏览(189)

我正在创建一个从DataGridView派生的自定义控件。我希望有一个搜索功能,它可以突出显示对单元格文本的搜索结果。下面是我目前所拥有的功能:

protected override void OnCellPainting(DataGridViewCellPaintingEventArgs e)
{
    if ((e.RowIndex <= -1) || (e.ColumnIndex <= -1) || string.IsNullOrWhiteSpace(HighlightedText) ||
        (e.Value is null) || (e.Value == DBNull.Value) || e.Value.GetType().IsImage())
    {
        base.OnCellPainting(e);
        return;
    }

    var cellText = e.FormattedValue.ToString();
    var ind = cellText.IndexOf(HighlightedText, StringComparison.OrdinalIgnoreCase);
    if (ind < 0)
    {
        base.OnCellPainting(e);
        return;
    }

    var newLineInd = cellText.IndexOf(Environment.NewLine);

    var rect = new Rectangle { Y = e.CellBounds.Y + 2 };

    var before = cellText[..ind];

    var flags = TextFormatFlags.TextBoxControl;

    //I tried this but doesn't seem to work
    var pos = e.CellStyle.Alignment switch
    {
        DataGridViewContentAlignment.TopLeft => TextFormatFlags.Top | TextFormatFlags.Left,
        DataGridViewContentAlignment.TopCenter => TextFormatFlags.Top | TextFormatFlags.HorizontalCenter,
        DataGridViewContentAlignment.TopRight => TextFormatFlags.Top | TextFormatFlags.Right,
        DataGridViewContentAlignment.MiddleLeft => TextFormatFlags.VerticalCenter | TextFormatFlags.Left,
        DataGridViewContentAlignment.MiddleCenter => TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter,
        DataGridViewContentAlignment.MiddleRight => TextFormatFlags.VerticalCenter | TextFormatFlags.Right,
        DataGridViewContentAlignment.BottomLeft => TextFormatFlags.Bottom | TextFormatFlags.Left,
        DataGridViewContentAlignment.BottomCenter => TextFormatFlags.Bottom | TextFormatFlags.HorizontalCenter,
        DataGridViewContentAlignment.BottomRight => TextFormatFlags.Bottom | TextFormatFlags.Right,
        _ => TextFormatFlags.Left,
    };

    flags |= pos;
    var match = cellText.Substring(ind, HighlightedText.Length);
    var sizeBefore = TextRenderer.MeasureText(e.Graphics, before, e.CellStyle.Font, e.CellBounds.Size, flags);
    var sizeMatch = TextRenderer.MeasureText(e.Graphics, match, e.CellStyle.Font, e.CellBounds.Size, flags);

    if (sizeBefore.Width > 5)
    {
        rect.X = e.CellBounds.X + sizeBefore.Width - 5;
        rect.Width = sizeMatch.Width - 6;

        //if match is on the new line
        if ((newLineInd != -1) && (ind > newLineInd))
        {
            var cellRow2Index = ind - newLineInd;
            var breakWord = cellText.Substring(newLineInd, cellRow2Index);
            var s3 = TextRenderer.MeasureText(e.Graphics, breakWord, e.CellStyle.Font, e.CellBounds.Size,
                                              TextFormatFlags.TextBoxControl);
            rect.X = e.CellBounds.X + 2 + s3.Width - 7;
            rect.Y = e.CellBounds.Y + sizeMatch.Height + 2;
        }
    }
    else
    {
        rect.X = e.CellBounds.X + 2;
        rect.Width = sizeMatch.Width - 6;
    }

    if (newLineInd == -1)
    {
        var sizeCell = TextRenderer.MeasureText(e.Graphics, cellText, e.CellStyle.Font, e.CellBounds.Size,
                                                TextFormatFlags.TextBoxControl);
        if (sizeCell.Width < e.CellBounds.Width)
        {
            rect.Y = e.CellBounds.Y + ((e.CellBounds.Height - sizeCell.Height) / 2);
        }
    }

    rect.Height = sizeMatch.Height;
    e.Handled = true;
    e.PaintBackground(e.CellBounds, true);
    e.Graphics.FillRectangle(_highlightBrush, rect);
    e.PaintContent(e.CellBounds);
}

正如你所看到的,计算并不精确,而且添加了很多随机数,这些随机数对不同的DPI不起作用。最重要的是,我不知道如何解释不同的文本位置。我试着使用e.CellStyle.Alignment来修改flags变量,但它不起作用。在下面的图片中,我突出显示了“19”:

jq6vz3qz

jq6vz3qz1#

谢谢@dr.null.根据您提供的链接,我写了以下内容:

protected override void OnCellPainting(DataGridViewCellPaintingEventArgs e)
{
    if ((e.RowIndex <= -1) || (e.ColumnIndex <= -1) || string.IsNullOrWhiteSpace(HighlightedText) ||
        (e.Value is null) || (e.Value == DBNull.Value) || e.Value.GetType().IsImage())
    {
        base.OnCellPainting(e);
        return;
    }

    var zeroWidth = "|";
    var cellText = e.FormattedValue.ToString().Replace(" ", zeroWidth);
    var highlight = HighlightedText.Replace(" ", zeroWidth);
    var ind = cellText.IndexOf(HighlightedText, StringComparison.OrdinalIgnoreCase);
    if (ind < 0)
    {
        base.OnCellPainting(e);
        return;
    }

    int linesBefore = 0;
    var totalLines = 1 + Regex.Matches(cellText, Environment.NewLine).Count;
    var newLineInd = cellText.IndexOf(Environment.NewLine);
    while (newLineInd >= 0 && newLineInd < ind)
    {
        linesBefore++;
        cellText = cellText[(newLineInd + Environment.NewLine.Length)..];
        ind = cellText.IndexOf(HighlightedText, StringComparison.OrdinalIgnoreCase);
        newLineInd = cellText.IndexOf(Environment.NewLine);
    }

    var g = e.Graphics;
    using var stringFormat = ConvertToStringFormat(e.CellStyle.Alignment);
    if(RightToLeft == RightToLeft.Yes)
    {
        stringFormat.FormatFlags |= StringFormatFlags.DirectionRightToLeft;
    }

    var zeroSize = g.MeasureString(zeroWidth, e.CellStyle.Font, e.CellBounds.Width, stringFormat).Width;
    var contentSize = g.MeasureString(cellText, e.CellStyle.Font, e.CellBounds.Width, stringFormat);
    var x = g.MeasureString(cellText[..ind], e.CellStyle.Font, e.CellBounds.Width, stringFormat).Width;
    var highlightWidth = g.MeasureString(cellText.Substring(ind, highlight.Length), e.CellStyle.Font,
        e.CellBounds.Width, stringFormat).Width;

    x = stringFormat.Alignment switch
    {
        StringAlignment.Center => x + ((e.CellBounds.Width - contentSize.Width) / 2) - (zeroSize / 2),
        StringAlignment.Far => x + (e.CellBounds.Width - contentSize.Width) - (zeroSize * 1.5f),
        StringAlignment.Near => x + (zeroSize / 2),
        _ => x
    };

    var totalContentHeight = totalLines * contentSize.Height;
    var top = stringFormat.LineAlignment switch
    {
        StringAlignment.Center => (e.CellBounds.Height - totalContentHeight) / 2,
        StringAlignment.Far => e.CellBounds.Bottom - totalContentHeight,
        StringAlignment.Near => 0,
        _ => 0
    };

    var y = top + (linesBefore * contentSize.Height);
    var highlightRect = new RectangleF(
        e.CellBounds.X + x,
        e.CellBounds.Y + y,
        highlightWidth,
        contentSize.Height);

    e.PaintBackground(e.CellBounds, true);
    g.FillRectangle(_highlightBrush, highlightRect);
    e.PaintContent(e.CellBounds);
    e.Handled = true;
}

相关问题