Don Kirkby
Don Kirkby

Reputation: 56650

How do I disable a button cell in a WinForms DataGrid?

I have a WinForms application with a DataGridView control and a column of DataGridViewButtonCell cells within that. When I click on one of these buttons, it starts a background task, and I'd like to disable the buttons until that task completes.

I can disable the DataGridView control, but it gives no visual indication that the buttons are disabled. I want the user to see that the buttons are disabled, and to notice that the task has finished when the buttons are enabled again.

Bonus points for a method that allows me to disable the buttons individually, so I can leave one of the buttons enabled while the task runs. (Note that I can't actually give out bonus points.)

Upvotes: 2

Views: 11828

Answers (2)

Don Kirkby
Don Kirkby

Reputation: 56650

Here's the best solution I've found so far. This MSDN article gives the source code for a cell class that adds an Enabled property.

It works reasonably well, but there are two gotchas:

  1. You have to invalidate the grid after setting the Enabled property on any cells. It shows that in the sample code, but I missed it.
  2. It's only a visual change, setting the Enabled property doesn't actually enable or disable the button. The user can still click on it. I could check the enabled property before executing the click event, but it also seemed to be messing up the appearance when the user clicked on it. Instead, I just disabled the entire grid. That works alright for me, but I'd prefer a method that allows me to disable some buttons without disabling the entire grid.

There's a similar sample in the DataGridView FAQ.

Upvotes: 3

Austin Salonen
Austin Salonen

Reputation: 50225

You could give this a try:

When you click on the cell...

  1. Check to see if the process with the current row identifier is running from a class-level list; if so, exit the cell click event.
  2. Store the row identifier in the class-level list of running processes.
  3. Change the button text to "Running..." or something appropriate.
  4. Attach a basic RunWorkerCompleted event handler to your process (explained shortly).
  5. Call backgroundWorker.RunWorkerAsync(rowIdentifier).

In the DoWork event handler...

  1. Set e.Result = e.Argument (or create an object that will return both the argument and your desired result)

In the RunWorkerCompleted event hanlder...

  1. Remove the row identifier from the running processes list (e.Result is the identifier).
  2. Change the button text from "Running..." to "Ready"

Upvotes: 1

Related Questions