首页 > 解决方案 > 如何在 DataGridView 中突出显示搜索阿拉伯语文本?

问题描述

我想在 DataGridView 中突出显示给定的搜索文本,但数据是阿拉伯语。我尝试了 CellPainting 事件来查找搜索文本的边界并绘制 FillRectangle,但我无法准确地获得搜索文本的边界。

用户界面

以下代码是我使用的代码:

private void dgv_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
    // High light and searching apply over selective fields of grid.  
    if (e.RowIndex > -1 && e.ColumnIndex > -1 && dgv.Columns[e.ColumnIndex].Name != "Id")
    {
        // Check data for search  
        if (!String.IsNullOrWhiteSpace(txtSearch.Text.Trim()))
        {
            String gridCellValue = e.Value.ToString();
            // check the index of search text into grid cell.  
            int startIndexInCellValue = gridCellValue.IndexOf(txtSearch.Text.Trim());
            // IF search text is exists inside grid cell then startIndexInCellValue value will be greater then 0 or equal to 0  
            if (startIndexInCellValue >= 0)
            {
                e.Handled = true;
                e.PaintBackground(e.CellBounds, true);
                //the highlite rectangle  
                Rectangle hl_rect = new Rectangle();
                hl_rect.Y = e.CellBounds.Y + 2;
                hl_rect.Height = e.CellBounds.Height - 5;
                //find the size of the text before the search word in grid cell data.  
                String sBeforeSearchword = gridCellValue.Substring(0, startIndexInCellValue);
                //size of the search word in the grid cell data  
                String sSearchWord = gridCellValue.Substring(startIndexInCellValue, txtSearch.Text.Trim().Length);
                Size s1 = TextRenderer.MeasureText(e.Graphics, sBeforeSearchword, e.CellStyle.Font, e.CellBounds.Size);
                Size s2 = TextRenderer.MeasureText(e.Graphics, sSearchWord, e.CellStyle.Font, e.CellBounds.Size);
                if (s1.Width > 5)
                {
                    hl_rect.X = e.CellBounds.Right + s1.Width - e.CellBounds.X - e.CellBounds.Left;
                    hl_rect.Width = s2.Width - 6;
                }
                else
                {
                    hl_rect.X = e.CellBounds.X + 2;
                    hl_rect.Width = s2.Width - 6;
                }
                //color for showing highlighted text in grid cell  
                SolidBrush hl_brush;
                hl_brush = new SolidBrush(Color.Yellow);
                //paint the background behind the search word  
                e.Graphics.FillRectangle(hl_brush, hl_rect);
                hl_brush.Dispose();
                e.PaintContent(e.CellBounds);
            }
        }
    }
}

标签: c#.netdatagridview

解决方案


问题


您需要考虑每个单元格的几个因素:

  • DataGridViewContentAlignment。_
  • 所选字符的确切大小。
  • 零宽度字符(空格)。
  • 内容的大小。
  • 空旷的空间。
  • 搜索字符串第一次出现的索引。

所有提到的都是计算和调整高亮矩形的位置和大小所必需的。

这是一个例子:

RTL 语言 - RTL 布局


private void dgv_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
    if (txtSearch.TextLength < 1 
        || e.RowIndex < 0 
        || e.ColumnIndex < 1
        || e.Value == null)
        return;

    var zeroWidth = "|";
    var v = e.Value.ToString().Replace(" ", zeroWidth);
    var f = txtSearch.Text.Replace(" ", zeroWidth);
    var i = v.IndexOf(f, StringComparison.InvariantCultureIgnoreCase);

    if (i < 0) return;

    e.Handled = true;
    var g = e.Graphics;

    using (var sf = ToStringFormat(e.CellStyle.Alignment))
    {
        var zw = g.MeasureString(zeroWidth, e.CellStyle.Font, e.CellBounds.Width, sf).Width;
        var valWidth = g.MeasureString(v, e.CellStyle.Font, e.CellBounds.Width, sf).Width;
        var w = g.MeasureString(f, e.CellStyle.Font, e.CellBounds.Width, sf).Width;
        var x = e.CellBounds.Right - ((e.CellBounds.Width - valWidth) / 2);

        x -= g.MeasureString(v.Substring(0, i), e.CellStyle.Font,
            e.CellBounds.Width, sf).Width;
        x -= w;

        switch (e.CellStyle.Alignment)
        {
            case DataGridViewContentAlignment.BottomLeft:
            case DataGridViewContentAlignment.MiddleLeft:
            case DataGridViewContentAlignment.TopLeft:
                x += ((e.CellBounds.Width - valWidth) / 2) - zw;
                break;
            case DataGridViewContentAlignment.MiddleRight:
            case DataGridViewContentAlignment.BottomRight:
            case DataGridViewContentAlignment.TopRight:
                x -= ((e.CellBounds.Width - valWidth) / 2) - zw;
                break;
            default:                        
                break;
        }

        var r = new RectangleF(
            x, 
            e.CellBounds.Y + 3, 
            w, 
            e.CellBounds.Height - 7);

        e.PaintBackground(e.CellBounds, true);
        g.FillRectangle(Brushes.Yellow, r);
        e.PaintContent(e.CellBounds);
    }
}

private StringFormat ToStringFormat(DataGridViewContentAlignment ca)
{
    var sf = StringFormat.GenericTypographic;

    switch (ca)
    {
        case DataGridViewContentAlignment.MiddleCenter:
            sf.Alignment = StringAlignment.Center;
            sf.LineAlignment = StringAlignment.Center;
            break;
        case DataGridViewContentAlignment.MiddleLeft:
            sf.Alignment = StringAlignment.Near;
            sf.LineAlignment = StringAlignment.Center;
            break;
        case DataGridViewContentAlignment.MiddleRight:
            sf.Alignment = StringAlignment.Far;
            sf.LineAlignment = StringAlignment.Center;
            break;
        case DataGridViewContentAlignment.BottomCenter:
            sf.Alignment = StringAlignment.Center;
            sf.LineAlignment = StringAlignment.Far;
            break;
        case DataGridViewContentAlignment.BottomLeft:
            sf.Alignment = StringAlignment.Near;
            sf.LineAlignment = StringAlignment.Far;
            break;
        case DataGridViewContentAlignment.BottomRight:
            sf.Alignment = StringAlignment.Far;
            sf.LineAlignment = StringAlignment.Far;
            break;
        case DataGridViewContentAlignment.TopLeft:
            sf.Alignment = StringAlignment.Near;
            sf.LineAlignment = StringAlignment.Near;
            break;
        case DataGridViewContentAlignment.TopRight:
            sf.Alignment = StringAlignment.Far;
            sf.LineAlignment = StringAlignment.Near;
            break;
        case DataGridViewContentAlignment.TopCenter:
            sf.Alignment = StringAlignment.Center;
            sf.LineAlignment = StringAlignment.Near;
            break;
    }

    sf.FormatFlags |= StringFormatFlags.DirectionRightToLeft;

    return sf;
}

这是一个演示。

SOQ60983817A

注意:演示中仅将 DGV 设置为 RTL 布局。

LTR 语言 - LTR 布局


也许超出范围,但可能对某人有用。

private void dgv_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
    if (txtSearch.TextLength < 1
        || e.RowIndex < 0
        || e.ColumnIndex < 1
        || e.Value == null)
        return;

    var zeroWidth = "|";
    var v = e.Value.ToString().Replace(" ", zeroWidth);
    var f = txtSearch.Text.Replace(" ", zeroWidth);
    var i = v.IndexOf(f, StringComparison.InvariantCultureIgnoreCase);

    if (i < 0) return;

    e.Handled = true;

    var g = e.Graphics;

    using (var sf = ToStringFormat(e.CellStyle.Alignment))
    {
        var zs = g.MeasureString(zeroWidth, e.CellStyle.Font, 
            e.CellBounds.Width, sf).Width;
        var valWidth = g.MeasureString(v, e.CellStyle.Font, 
            e.CellBounds.Width, sf).Width;
        var x = g.MeasureString(v.Substring(0, i), e.CellStyle.Font, 
            e.CellBounds.Width, sf).Width;
        var w = g.MeasureString(v.Substring(i, f.Length), e.CellStyle.Font, 
            e.CellBounds.Width, sf).Width;


        switch (e.CellStyle.Alignment)
        {
            case DataGridViewContentAlignment.MiddleCenter:
            case DataGridViewContentAlignment.BottomCenter:
            case DataGridViewContentAlignment.TopCenter:
                x += (e.CellBounds.Width - valWidth) / 2;
                x -= zs / 2;
                break;
            case DataGridViewContentAlignment.MiddleRight:
            case DataGridViewContentAlignment.BottomRight:
            case DataGridViewContentAlignment.TopRight:
                x += (e.CellBounds.Width - valWidth);
                x -= zs * 1.5f;
                break;
            default:
                x += zs / 2;
                break;
        }

        var r = new RectangleF(
            e.CellBounds.X + x,
            e.CellBounds.Y + 3,
            w,
            e.CellBounds.Height - 7);

        e.PaintBackground(e.CellBounds, true);
        g.FillRectangle(Brushes.Yellow, r);
        e.PaintContent(e.CellBounds);
    }
}

private StringFormat ToStringFormat(DataGridViewContentAlignment ca)
{
    var sf = StringFormat.GenericTypographic;

    switch (ca)
    {
        case DataGridViewContentAlignment.MiddleCenter:
            sf.Alignment = StringAlignment.Center;
            sf.LineAlignment = StringAlignment.Center;
            break;
        case DataGridViewContentAlignment.MiddleLeft:
            sf.Alignment = StringAlignment.Near;
            sf.LineAlignment = StringAlignment.Center;
            break;
        case DataGridViewContentAlignment.MiddleRight:
            sf.Alignment = StringAlignment.Far;
            sf.LineAlignment = StringAlignment.Center;
            break;
        case DataGridViewContentAlignment.BottomCenter:
            sf.Alignment = StringAlignment.Center;
            sf.LineAlignment = StringAlignment.Far;
            break;
        case DataGridViewContentAlignment.BottomLeft:
            sf.Alignment = StringAlignment.Near;
            sf.LineAlignment = StringAlignment.Far;
            break;
        case DataGridViewContentAlignment.BottomRight:
            sf.Alignment = StringAlignment.Far;
            sf.LineAlignment = StringAlignment.Far;
            break;
        case DataGridViewContentAlignment.TopLeft:
            sf.Alignment = StringAlignment.Near;
            sf.LineAlignment = StringAlignment.Near;
            break;
        case DataGridViewContentAlignment.TopRight:
            sf.Alignment = StringAlignment.Far;
            sf.LineAlignment = StringAlignment.Near;
            break;
        case DataGridViewContentAlignment.TopCenter:
            sf.Alignment = StringAlignment.Center;
            sf.LineAlignment = StringAlignment.Near;
            break;
    }

    return sf;
}

SOQ60983817B


推荐阅读