WinForms - DataGridViewCell не устанавливается только для чтения

Я работаю над старым проектом .Net 2.0 WinForms и должен установить некоторые ячейки только для чтения.

У меня есть DataTable, который я читаю и устанавливаю, когда DataSource и типы полей устанавливаются правильно.

Создать DataTable и столбцы

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;
    }

Вышеупомянутый метод вызывается здесь, и именно здесь возникает проблема отключения ячеек.

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;
                    }
                }
            }
        }

    }

Когда вы переходите и смотря на окно Watch, я вижу, что устанавливаются свойства только для чтения, однако при работе с DataGridView ячейки все еще активны.

Я был бы признателен, если бы кто-нибудь мог указать мне в сторону, где этот код неправильный или мне нужно сделать что-то еще?

Спасибо за вашу помощь.

--- Редактировать 31/05/2017

введите описание изображения здесь

На изображении выше показана сетка, с которой я хочу работать, и выбранные параметры выбираются по умолчанию.

Параметры, которые не выбраны, должны быть отключены, потому что эти формы доставки невозможны для почтового типа

Ответ 1

Я проверил это в небольшом проекте образца, и это сработало для меня:

// 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);
    }
}

Далее вы можете добавить событие, чтобы отслеживать изменения ячеек, чтобы активировать чтение только для нажатых ячеек:

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);
}

(Пожары после того, как было сделано изменение, и ячейка осталась.)

Вы можете создать образец проекта со скрипкой из Иван Стоев в 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;
        }
    }
}

Ответ 2

Попробуйте это

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

Надеюсь, это сработает для вас.

Ответ 3

С моей точки зрения, при заполнении, если начальное значение флажка установлено false, оно должно быть прочитано только.

Попробуйте установить значение только для чтения, используя следующие

// 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;                 
        }
    }
}

Ответ 4

EDIT:

Хорошо, я понял, что код скрипки не принадлежит вам (я должен был прочитать более внимательно). Я смог воссоздать это, используя код из вашего вопроса. Я вижу, что проблема сейчас, это та строка:

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

Вы тестируете "Выбранный", который не то, что вы хотите, вы хотите протестировать "Значение" ячейки.

Если вы посмотрите на код в других ответах, это то, что они показывают.

Исходный ответ: Left для других

Выполняя свой код (скрипка), флажки действительно читаются, хотя они не отображаются серым цветом, как если бы они были отключены (это то, что я думаю, что вы ищете). Можете ли вы подтвердить, действительно ли вы можете проверить флажки или не?

К сожалению, вы не можете отключить этот флажок напрямую.

Если это то, что вы хотите, тогда у вас есть пара опций, вы можете либо изменить BackColor ячейки, что может быть достаточно, но это фактически не изменит цвет самого флажка.

Вы также можете сами нарисовать элемент управления, здесь - это руководство по микрософт для аналогичного руководства.

Или вы можете создать отключенную ячейку и заменить те, которые вам нужны. Это не слишком много работает, особенно когда кто-то уже сделал это для вас!