问题
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