Simon Price
Simon Price

Reputation: 3271

WinForms - DataGridViewCell not being set to read only

I am working on an old .Net 2.0 WinForms project and need to set some cells to read only.

I have a DataTable that I am reading and setting as the DataSource and the field types are being set correctly

Generate DataTable and columns

public DataTable FilterData(DataTable datatable, string dataType)
    {
        try
        {
            if (dataType == "MailPreferences")
            {

                var dt = new DataTable();

                dt.Columns.Add("SEQ_ID", typeof(int));                              // SEQ_ID
                dt.Columns.Add("MAIL_PREFERENCE_ID", typeof(string));               // MAIL_PREFERENCE_ID
                dt.Columns.Add("Mail Preference Description", typeof(string));      // MAIL_PREFERENCE_DESC
                dt.Columns.Add("Post", typeof(bool));                               // POST
                dt.Columns.Add("SMS", typeof(bool));                                // SMS
                dt.Columns.Add("Email", typeof(bool));                              // EMAIL
                dt.Columns.Add("Telephone", typeof(bool));                          // TELEPHONE

                foreach (DataRow row in datatable.Rows)
                {
                    dt.Rows.Add(row["SEQ_ID"].ToString(), 
                                row["MAIL_PREFERENCE_ID"].ToString(), 
                                row["MAIL_PREFERENCE_DESC"].ToString(),
                                Convert.ToBoolean(row["POST"]), 
                                Convert.ToBoolean(row["SMS"]), 
                                Convert.ToBoolean(row["EMAIL"]),
                                Convert.ToBoolean(row["TELEPHONE"]));
                }

                return dt;

            }


        }
        catch (Exception ex)
        {
            // catch and deal with my exception here
        }

        return null;
    }

The above method is being called here and this is where I am having the issue of disabling cells.

private void PopulateMailPreferencesGV()
    {
        var dt = FilterData(_cAddPersonWizard.GetMailPreferneces(), "MailPreferences");
        dgvMailPreferences.DataSource = dt;

        dgvMailPreferences.Columns["Mail Preference Description"].Width = 250;
        dgvMailPreferences.Columns["Post"].Width = 50;
        dgvMailPreferences.Columns["SMS"].Width = 50;
        dgvMailPreferences.Columns["Email"].Width = 50;
        dgvMailPreferences.Columns["Telephone"].Width = 75;

        dgvMailPreferences.Columns["SEQ_ID"].Visible = false;
        dgvMailPreferences.Columns["MAIL_PREFERENCE_ID"].Visible = false;


        // not setting the datagridview cell to readonly
        foreach (DataGridViewRow row in dgvMailPreferences.Rows)
        {
            foreach (DataGridViewCell cell in row.Cells)
            {
                if (cell.GetType() == typeof(DataGridViewCheckBoxCell))
                {
                    if(((DataGridViewCheckBoxCell)row.Cells[cell.ColumnIndex]).Selected == false)
                    {
                        ((DataGridViewCheckBoxCell)row.Cells[cell.ColumnIndex]).ReadOnly = true;
                    }
                }
            }
        }

    }

When stepping through and looking at the Watch window I can see that the read only properties are being set, however when coming to work with the DataGridView the cells are still active.

I would be grateful if someone could point me in the direction of where this code is wrong or if I need to do something else?

Thanks for your help.

--- Edit 31/05/2017

enter image description here

The image above shows the grid that I want to work with, the options that are selected are selected by default.

The options that are not selected are to be disabled because these forms of delivery are not possible for the mail type

Upvotes: 10

Views: 3062

Answers (4)

Reznoir
Reznoir

Reputation: 939

EDIT:

Ok I realised that the fiddle code wasn't yours (I should have read more carefully). I was able to recreate this using the code from your question. I see what the problem is now, it is this line:

if(((DataGridViewCheckBoxCell)row.Cells[cell.ColumnIndex]).Selected == false)

You are testing against 'Selected' which is not what you want, you want to test against the 'Value' of the cell.

If you look at the code in the other answers this is what they show.

Original Answer: Left for others

Running your code (fiddle) the checkboxes are indeed readonly although they do not appear grayed out as if they were disabled (which is what I think you are looking for) Can you confirm if you are able to actually check the checkboxes or not?

Unfortunately you can not disable the checkbox directly.

If this is what you want then you have a couple of options, you can either change the BackColor of the cell, which may be sufficient, however this will not actually change the colour of the checkbox itself.

You can also paint the control yourself, here is a microsoft guide to a similar tutorial.

Or you could create a disabled cell and replace the ones that you need with that. It's not too much work, especially when someone has already done it for you!

Upvotes: 0

Nik Bo
Nik Bo

Reputation: 1410

I had checked this in a small sample project and this worked for me:

// Loop through all the rows of your grid
foreach (DataGridViewRow row in this.dgvMailPreferences.Rows)
{
    // Loop through all the cells of the row
    foreach (DataGridViewCell cell in row.Cells)
    {
        // Check if the cell type is CheckBoxCell
        // If not, check the next cell
        if (!(cell is DataGridViewCheckBoxCell)) continue;

        // Set the specific cell to read only, if the cell is not checked
        cell.ReadOnly = !Convert.ToBoolean(cell.Value);
    }
}

Further you can add an event to track cell changes to activate read only for clicked cells:

private void dgvMailPreferences_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
    if (!(e.RowIndex >= 0 && e.ColumnIndex >= 0)) return;

    DataGridViewCell cell = ((DataGridView)sender).Rows[e.RowIndex].Cells[e.ColumnIndex];

    if (!(cell is DataGridViewCheckBoxCell)) return;

    cell.ReadOnly = !System.Convert.ToBoolean(cell.Value);
}

(Fires after a change was done and the cell was left.)

You can build a sample project with the fiddle from Ivan Stoev at Dotnetfiddle

using System;
using System.Collections.Generic;
using System.Data;
using System.Windows.Forms;

namespace Samples
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            var form = new Form();
            var dgv = new DataGridView { Dock = DockStyle.Fill, Parent = form };
            form.Load += (sender, e) =>
            {
                var dt = GetData();
                dgv.DataSource = dt;
                dgv.Columns["Mail Preference Description"].Width = 250;
                dgv.Columns["Post"].Width = 50;
                dgv.Columns["SMS"].Width = 50;
                dgv.Columns["Email"].Width = 50;
                dgv.Columns["Telephone"].Width = 75;
                dgv.Columns["SEQ_ID"].Visible = false;
                dgv.Columns["MAIL_PREFERENCE_ID"].Visible = false;
                foreach (DataGridViewRow row in dgv.Rows)
                {
                    foreach (DataGridViewCell cell in row.Cells)
                    {
                        if (cell.Value is bool && (bool)cell.Value == false)
                            cell.ReadOnly = true;
                    }
                }
            };
            Application.Run(form);
        }

        static DataTable GetData()
        {
            var dt = new DataTable();
            dt.Columns.Add("SEQ_ID", typeof(int));                              // SEQ_ID
            dt.Columns.Add("MAIL_PREFERENCE_ID", typeof(string));               // MAIL_PREFERENCE_ID
            dt.Columns.Add("Mail Preference Description", typeof(string));      // MAIL_PREFERENCE_DESC
            dt.Columns.Add("Post", typeof(bool));                               // POST
            dt.Columns.Add("SMS", typeof(bool));                                // SMS
            dt.Columns.Add("Email", typeof(bool));                              // EMAIL
            dt.Columns.Add("Telephone", typeof(bool));                          // TELEPHONE

            dt.Rows.Add(1, "1", "Membership", true, true, true, true);
            dt.Rows.Add(2, "2", "Monthly Newsletter", false, false, true, false);
            dt.Rows.Add(3, "3", "Mothhly Technical Briefing", false, false, true, false);
            dt.Rows.Add(4, "4", "Magazine", false, false, true, false);
            dt.Rows.Add(5, "5", "Branch Mailings", false, true, true, false);
            dt.Rows.Add(6, "6", "Events", true, true, true, true);
            dt.Rows.Add(7, "7", "Qualifications", true, true, true, true);
            dt.Rows.Add(8, "8", "Training", true, true, true, true);
            dt.Rows.Add(9, "9", "Recruitment", true, true, true, true);
            dt.Rows.Add(10, "A", "General", true, true, true, true);

            return dt;
        }
    }
}

Upvotes: 5

user2922221
user2922221

Reputation:

Try this

((DataGridViewCheckBoxCell)Rows[Index].Cells["colName"]).ReadOnly = true;

Hopefully it will work for you.

Upvotes: 1

Nkosi
Nkosi

Reputation: 247561

From my understanding, when populating, if the initial value of the checkbox is false then it should be read only.

Try setting the read only value using the following

// not setting the datagridview cell to readonly
foreach (DataGridViewRow row in dgvMailPreferences.Rows) {
    foreach (DataGridViewCell cell in row.Cells) {
        if (cell is DataGridViewCheckBoxCell) {
            DataGridViewCheckBoxCell checkBoxCell = cell as DataGridViewCheckBoxCell;
            //What is the initial  value in the checkbox
            bool isChecked = checkBoxCell.Value as bool;
            //set to read only if not checked
            checkBoxCell.ReadOnly = !isChecked;                 
        }
    }
}

Upvotes: 0

Related Questions