How to highlight search Arabic text in DataGridView?

纵然是瞬间 提交于 2020-04-16 12:47:28

问题


I want to highlight the given search text in the DataGridView but the data is in Arabic. I have tried CellPainting event to find the bounds of the search text and draw FillRectangle, but I could not exactly get the bounds of the search text.

The following code was the one I used:

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);
            }
        }
    }
}

回答1:


Problem


You need to take into account several factors for each cell:

  • The DataGridViewContentAlignment.
  • The exact size of the selected characters.
  • The zero-width characters (white spaces).
  • The size of the content.
  • The empty space.
  • The index of the first occurrence of the search string.

All the mentioned are necessary to calculate and adjust both the location and size of the highlight rectangle.

Here's an example:

RTL Languages - RTL Layout


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;
}

Here's a demo.

Note: Only the DGV is set to RTL layout in the demo.

LTR Languages - LTR Layout


Maybe out of scope, however might be useful for someone.

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;
}



来源:https://stackoverflow.com/questions/60983817/how-to-highlight-search-arabic-text-in-datagridview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!