I am using a DataGridView to display locks (by user, assigned by the application) in the associated database.
The user is presented with a list of current locks, showing the relevant information, and the last visible column is a DataGridViewImageColumn, with the image fed from the application resources.

在末尾还有一个隐藏的DataGridViewCheckBoxColumn,当用户双击一行的图标时,它被选中,而如果用户双击该行的相同图标,即重置他们的 Select ,则取消选中.

What I'm trying to do is, based on the value of the checkbox, swap the image and tooltip in the CellContentDoubleClick event, as below, but I'm not seeing the change to the icon or the tooltip.
'ProjectLocked' is the name of the DataGridViewImageColumn and 'DeleteLock' is the name of the DataGridViewCheckBoxColumn.

private void dgvProjectLocks_CellContentDoubleClick(object sender, DataGridViewCellEventArgs e)
{
    // do nothing for the header row
    if (e.RowIndex < 0) return;
    // caste the object to the correct type
    var dgv = (DataGridView)sender;
    // Do nothing if the clicked column is not the ProjectLocked column
    if (dgv.Columns[e.ColumnIndex].Name != "ProjectLocked") return;
    // Get the clicked row
    using (var currentRow = dgv.Rows[e.RowIndex])
    {
        using (var deleteCell = currentRow.Cells["DeleteLock"])
        {
            switch (Convert.ToBoolean(deleteCell.Value))
            {
                case true:
                    currentRow.DefaultCellStyle.BackColor = dgv.DefaultCellStyle.BackColor;
                    currentRow.DefaultCellStyle.ForeColor = dgv.DefaultCellStyle.ForeColor;
                    deleteCell.Value = false;
                    currentRow.Cells["ProjectLocked"].Value = Resources.locked;
                    deleteCell.ToolTipText = Resources.AddProjectLockDeleteToolTip;
                    break;
                case false:
                    currentRow.DefaultCellStyle.BackColor = Color.LightGray;
                    currentRow.DefaultCellStyle.ForeColor = Color.DarkGray;
                    deleteCell.Value = true;
                    currentRow.Cells["ProjectLocked"].Value = Resources.unlocked;
                    deleteCell.ToolTipText = Resources.RemoveProjectLockDeleteToolTip;
                    break;
            }
        }
    }
}

推荐答案

Note: Properties.Resources is a Factory, it returns a new object each time you ask for one. When you assign a new object from the Resource, the object it replaces is left to the GC. In case of Graphics objects, not a good thing. Better cache these objects and use the cached value.
Here I'm using a Dictionary<bool, Image> as storage facility:

private Dictionary<bool, Image> DataGridViewLockState = new Dictionary<bool, Image>() {
    [true]  = Resources.locked,
    [false] = Resources.unlocked
};

关于此处提供的代码:

  • When you assign a reference to a local variable, don't declare it with a using statement. You need the referenced object alive, here, those are your Rows / Cells
    You're setting the ToolTip of a Cell that, as you have mentioned, belongs to a hidden CheckBox Column. I assume you want to set the ToolTip of the Image Column, so you can see it.

其他:

  • 测试e.RowIndexe.ColumIndex的负值,因为两者都可能是负值(您可能已经禁用了列排序,没关系,它是procedural)
  • 最好还测试单元格的值是null还是DbNull.Value.如果数据不是从数据库中出来的,那也没关系,安全总比后悔好

When you have changed the current state of the affected Cells, call the [DataGridView].EndEdit() method. This commits the changes immediately.
It also raises the CellValueChanged event immediately, before the current event has completed. Keep this in mind if you have code in the CellValueChanged handler.
Better call EndEdit() last, to avoid some form of re-entrancy


private void dgvTest_CellContentDoubleClick(object sender, DataGridViewCellEventArgs e) {
    var dgv = sender as DataGridView;
    if (dgv is null || e.RowIndex < 0 || e.ColumnIndex < 0) return;
    if (dgv.Columns[e.ColumnIndex].Name != "ProjectLocked") return;

    var currentRow = dgv.Rows[e.RowIndex];
    var deleteCell = currentRow.Cells["DeleteLock"];

    if (deleteCell.Value is null || deleteCell.Value == DBNull.Value) {
        throw new InvalidOperationException("DeleteLock value cannot be null");
    }

    // Negate the current value, we want to change state
    bool value = !(bool)deleteCell.Value;

    currentRow.Cells["ProjectLocked"].Value = DataGridViewLockState[value];
    currentRow.Cells["ProjectLocked"].ToolTipText = value ? Resources.RowLocked : Resources.RowUnlocked;
    currentRow.DefaultCellStyle.BackColor = value ? dgv.DefaultCellStyle.BackColor : Color.LightGray;
    currentRow.DefaultCellStyle.ForeColor = value ? dgv.DefaultCellStyle.ForeColor : Color.DarkGray;
    deleteCell.Value = value;
    dgv.EndEdit();
}

Csharp相关问答推荐

为什么我在PuppeteerSharp中运行StealthPlugin时会出现错误?

.NET框架4.7.2项目如何引用.NET Core 2.2库?

如何循环遍历XML文档 node 以使用XSLT存储值

. NET在上一个操作完成之前,在此上下文实例上启动了第二个操作

如何在Visual Studio代码中更改大括号模式{},用于C#语言

如何修改中间件或其注册以正确使用作用域服务?

Unity中的刚体2D运动

如何测量在使用UTF8而不是C#中的UTF16编码字符串时内存使用量的增长

C#和ASP.NET核心标识:提高GetUserAsync调用的性能

从VS调试器而不是测试资源管理器运行的调试NUnitDotNet测试

如何将DotNet Watch与发布配置和传递给应用程序的参数一起使用?

在';、';附近有错误的语法.必须声明标量变量";@Checkin";.';

解决方案:延长ABP框架和ANGING OpenIddict中的令牌生命周期

EF Core:如何对关系属性进行建模?

如何正确处置所有动态控件?

WPF:如何从DatagridHeader的内容模板绑定到词典项

C#中COM对象的实际地址

我可以阻止类型上的Object.ToString()吗?

反编译源代码时出现奇怪的字符

C#LINQ多行条件