Winforms:验证 datagridview 中的单元格时出现问题

发布于 2024-12-09 11:04:13 字数 520 浏览 0 评论 0原文

我想使用 CellValidating 验证 Winforms datagridview 单元格。如果用户未正确设置值,我会设置 ErrorText 并使用 e.Cancel,以便光标保留在单元格中。 现在的问题是,错误符号(和错误文本)未显示(在单元格中)。当我删除 e.Cancel 时,单元格失去焦点并显示错误符号。如何才能使单元格保持在编辑模式并且也显示错误符号?

if (...)
{
   this.datagridviewX.Rows[e.RowIndex].Cells[e.ColumnIndex].ErrorText = "Errortext";
   e.Cancel = true;
}
else
{
   this.datagridviewX.Rows[e.RowIndex].Cells[e.ColumnIndex].ErrorText = "";
}

I want to validate a Winforms datagridview cell with CellValidating. If a value was not set correctly by the user I set ErrorText and use e.Cancel, so that the cursor remains in the cell.
The problem is now, that the error-symbol (and the error text) is not displayed (in the cell). When I delete e.Cancel the cell looses the focus and error-symbol is displayed. How can I achieve that the cell remains in edit mode and the error-symbol is displayed too?

if (...)
{
   this.datagridviewX.Rows[e.RowIndex].Cells[e.ColumnIndex].ErrorText = "Errortext";
   e.Cancel = true;
}
else
{
   this.datagridviewX.Rows[e.RowIndex].Cells[e.ColumnIndex].ErrorText = "";
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

征棹 2024-12-16 11:04:13

您所看到的行为实际上是由于绘画问题造成的,而不是由于未显示错误图标造成的。发生的情况是,当您设置单元格的错误文本时,会显示图标,但编辑模式下单元格的文本框会绘制在图标上,因此不会向用户显示图标!

您有两种选择来解决此问题 - 一种是简单地使用该行的错误文本,而不是:

this.datagridviewX.Rows[e.RowIndex].Cells[e.ColumnIndex].ErrorText = "Errortext";  
e.Cancel = true;  

您有:

this.datagridviewX.Rows[e.RowIndex].ErrorText = "Errortext";
e.Cancel = true;

另一种选择是更改单元格的单元格填充(移动编辑控件)并绘制图标。

实际上,我找到了解决问题的技术此处并复制了他们的代码下面(在 C# 中而不是 VB.Net 中)。

首先,您有单元格验证事件,您可以在其中添加一些代码来更改单元格填充:

void dataGridView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
    if (string.IsNullOrEmpty(e.FormattedValue.ToString()))
    {
        DataGridViewCell cell = dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex];

        cell.ErrorText =
            "Company Name must not be empty";

        if (cell.Tag == null)
        {
            cell.Tag = cell.Style.Padding;
            cell.Style.Padding = new Padding(0, 0, 18, 0);
        }
        e.Cancel = true;

    }
    else
    {
        dataGridView1.Rows[e.RowIndex].ErrorText = string.Empty;
    }
}

这允许在编辑控件移动时看到图标,但图标也移动了!所以我们还需要绘制一个新的图标。

void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
    if (dataGridView1.IsCurrentCellDirty)
    {
        if (!string.IsNullOrEmpty(e.ErrorText))
        {
            GraphicsContainer container = e.Graphics.BeginContainer();
            e.Graphics.TranslateTransform(18,0);
            e.Paint(this.ClientRectangle, DataGridViewPaintParts.ErrorIcon);
            e.Graphics.EndContainer(container);
            e.Handled = true;
        }
    }
}

然后,当您结束对单元格的编辑时,您需要重置填充:

void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
    if (!string.IsNullOrEmpty(dataGridView1[e.ColumnIndex, e.RowIndex].ErrorText))
    {
        DataGridViewCell cell = dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex];
        cell.ErrorText = string.Empty;
        cell.Style.Padding = (Padding)cell.Tag;
        cell.Tag = null;
    }
}

我发现此帖子忽略将鼠标悬停在新绘制的图标上 - 这是一些解决该问题的粗略代码,我没有时间获取它真的很有效,所以有一些轻微的错误,我认为可以解决 - 如果我稍后得到,我会整理它。

我设置 DataGridView.ShowCellToolTips = true 并引入布尔值 inError 来跟踪当前是否存在编辑错误。然后,我处理 MouseHover 事件:

void dataGridView1_MouseHover(object sender, EventArgs e)
{
    if (inError)
    {                
        Point pos = this.PointToClient(Cursor.Position);               

        if (r.Contains(pos.X - 20, pos.Y - 5))
        {                   
            t.Show("There was an error", dataGridView1.EditingControl, 3000); 
        }
    }
}

该代码中的 t 是表单级 ToolTip 控件,r 是矩形。

我在单元格绘制处理程序中按如下方式填充 r:

void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
    if (dataGridView1.IsCurrentCellDirty)
    {
        if (!string.IsNullOrEmpty(e.ErrorText))
        {            
            GraphicsContainer container = e.Graphics.BeginContainer();

            r = dataGridView1.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, true);
            e.Graphics.TranslateTransform(18, 0);
            e.Paint(this.ClientRectangle, DataGridViewPaintParts.ErrorIcon);
            e.Graphics.EndContainer(container);            

            e.Handled = true;
        }
    }
}

我对位置点上的负 20 和负 5 不满意 - 如果我有更多时间,这就是我要修复的问题。

The behaviour you are seeing is actually due to a painting issue and not due to the error icon not being shown. What is happening is that when you set the cell's error text the icon is displayed but the text box of the cell in edit mode is painted over the icon, hence no icon shown to the user!

You have two options for fixing this - one is to simply use the row's error text so instead of:

this.datagridviewX.Rows[e.RowIndex].Cells[e.ColumnIndex].ErrorText = "Errortext";  
e.Cancel = true;  

You have:

this.datagridviewX.Rows[e.RowIndex].ErrorText = "Errortext";
e.Cancel = true;

The other option is to change the cell padding of the cell (moving the editing control) and painting the icon in.

I actually found this technique for solving the problem here and reproduced their code below (in C# and not VB.Net).

First you have your cell validating event where you add some code to change the cell padding:

void dataGridView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
    if (string.IsNullOrEmpty(e.FormattedValue.ToString()))
    {
        DataGridViewCell cell = dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex];

        cell.ErrorText =
            "Company Name must not be empty";

        if (cell.Tag == null)
        {
            cell.Tag = cell.Style.Padding;
            cell.Style.Padding = new Padding(0, 0, 18, 0);
        }
        e.Cancel = true;

    }
    else
    {
        dataGridView1.Rows[e.RowIndex].ErrorText = string.Empty;
    }
}

That allows the icon to be seen not the editing control has moved, except the icon has moved too! So we also need to paint a new icon.

void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
    if (dataGridView1.IsCurrentCellDirty)
    {
        if (!string.IsNullOrEmpty(e.ErrorText))
        {
            GraphicsContainer container = e.Graphics.BeginContainer();
            e.Graphics.TranslateTransform(18,0);
            e.Paint(this.ClientRectangle, DataGridViewPaintParts.ErrorIcon);
            e.Graphics.EndContainer(container);
            e.Handled = true;
        }
    }
}

Then when you end editing on the cell you need to reset the padding:

void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
    if (!string.IsNullOrEmpty(dataGridView1[e.ColumnIndex, e.RowIndex].ErrorText))
    {
        DataGridViewCell cell = dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex];
        cell.ErrorText = string.Empty;
        cell.Style.Padding = (Padding)cell.Tag;
        cell.Tag = null;
    }
}

The post where I found this neglects to set the mouse over for the new painted icon - Here is some rough code that addresses that, I don't have time to get it really working so there are some slight fudges that thought would fix - I'll tidy that up if I get a minute later.

I set DataGridView.ShowCellToolTips = true and introduce a boolean inError to track if we currently have an editing error. I then handle the MouseHover event:

void dataGridView1_MouseHover(object sender, EventArgs e)
{
    if (inError)
    {                
        Point pos = this.PointToClient(Cursor.Position);               

        if (r.Contains(pos.X - 20, pos.Y - 5))
        {                   
            t.Show("There was an error", dataGridView1.EditingControl, 3000); 
        }
    }
}

The t in that code is a form level ToolTip control, and r is a rectangle.

I populate r as below in the cell painting handler:

void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
    if (dataGridView1.IsCurrentCellDirty)
    {
        if (!string.IsNullOrEmpty(e.ErrorText))
        {            
            GraphicsContainer container = e.Graphics.BeginContainer();

            r = dataGridView1.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, true);
            e.Graphics.TranslateTransform(18, 0);
            e.Paint(this.ClientRectangle, DataGridViewPaintParts.ErrorIcon);
            e.Graphics.EndContainer(container);            

            e.Handled = true;
        }
    }
}

I'm not happy about the minus 20 and minus 5 on the position point - that is what I'd fix up if I had a bit more time.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文