views:

103

answers:

2

Software I use: C#, VS-2005.

I have a populated combobox in datagridview. I have noticed that when the datagridview property RowHeaderVisible is set to false then no keydown event is fired on editing control. But when I set RowHeaderVisible to true, the keydown event works fine.

So, I know that the RowHeaderVisible property set to true will work. But there is no need to set it to true as per my requirement.

I want to know the reason for this behavior, and how to overcome it.

My Code Is :

private void Form1_Load(object sender, EventArgs e)

{          
        string consstr = "server=.;initial   
        catalog=mydatabase;uid=myuserid;pwd=mypassword";
        SqlConnection conn = new SqlConnection(consstr);
        conn.Open();
        string sql = "select accname from AccountMast";
        SqlDataAdapter dap = new SqlDataAdapter(sql, conn);
        DataSet ds = new DataSet();
        dap.Fill(ds);
        DataTable dt = new DataTable();
        DataGridViewComboBoxColumn cmb = new DataGridViewComboBoxColumn();
        dataGridView1.Columns.Add(cmb);
        cmb.DataSource = ds.Tables[0];
        cmb.DisplayMember = "accname";
        cmb.ValueMember = "accname";
        dt.Columns.Add("AMOUNT", typeof(decimal));
        dataGridView1.DataSource = dt;
        dataGridView1.Columns[0].Width = 300;
        dataGridView1.Columns[1].Width = 143;
        dataGridView1.Columns[1].DefaultCellStyle.Format = "f2";
    }
   private void dataGridView1_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.Alt == true && e.KeyCode == Keys.C) 
        {
            Form2 f2 = new Form2();
            f2.Show();
         }
    }

The above code is represent entry point. I mean user enter the data on it. I have populate combobox in datagridview with database of sql. The combobox having list of account name. user select it as per their demand and than enter data on column of amount and save it.

That's all. but there is a problem you can see it. as per my comment lying below the "tergive's" answer.

A: 

Control doesn't provide a good way to externally wire in a "command key" like that. The best place to look for command keys is to override ProcessCmdKey. So you basically have two choices:

1) Override ProcessCmdKey on your form and check during invocation if the DGV (or one of its children) has keyboard focus.

2) Create a custom DGV and override ProcessCmdKey there.

I have used #2 in the past and created something as follows to allow external access to the event (the parent form).

Expanded example

using System;
using System.Windows.Forms;

class Form1 : Form
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }

    public Form1()
    {
        Text = "Form1";

        CustomDataGridView dgv = new CustomDataGridView();
        dgv.Dock = DockStyle.Fill;
        DataGridViewComboBoxColumn dgvColumn = new DataGridViewComboBoxColumn();
        dgvColumn.HeaderText = "Header";
        dgvColumn.DataSource = new string[] { "One", "Two", "Three", "Four" };
        dgv.Columns.Add(dgvColumn);
        dgv.CommandKeyPress += new CommandKeyPressHandler(dgv_CommandKeyPress);
        Controls.Add(dgv);

        Button button = new Button();
        button.Text = "Place holder";
        button.Dock = DockStyle.Top;
        Controls.Add(button);
    }

    bool dgv_CommandKeyPress(object sender, Keys keyData)
    {
        if ((keyData & (Keys.Alt | Keys.C)) == (Keys.Alt | Keys.C))
        {
            Form form = new Form();
            form.Text = "Form2";
            form.Show(this); 
            return true;
        }
        return false;
    }
}

delegate bool CommandKeyPressHandler(object sender, Keys keyData);

class CustomDataGridView : DataGridView
{
    public event CommandKeyPressHandler CommandKeyPress;

    protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
    {
        CommandKeyPressHandler eventDelegate = CommandKeyPress;
        if (eventDelegate != null)
        {
            foreach (CommandKeyPressHandler handler in eventDelegate.GetInvocationList())
            {
                if (handler(this, keyData))
                    return true;
            }
        }
        return base.ProcessCmdKey(ref msg, keyData);
    }
}
Tergiver
@Tergiver, I have tried it's not work, still it is there as usual. It is works on empty combobox not in case of combobox not empty
mahesh
@Tergiver, I Explain u in details that this is entry point datagrid where user enter the data. there are combobox which contains list of account name other column is of Amount. User select the list of account name from combobox and enter data into amount. and save it.
mahesh
by default in runtime combobox display as empty even though there is databound with sql database and when we press Alt+C then it's works but if you click on combobox it display the list of account and you select one of it then after if you press Alt+C it doesn't works. that's the problem.
mahesh
@Tergiver, if this kind of situation than how can u handle it. may be i wrong with above code but the correct way should be suggested it's my request. try to understand it if i miss some thing.
mahesh
@Tergiver, The above code means my code.
mahesh
@mahesh: Using ProcessCmdKey works, even if the combo box contains data. ProcessCmdKey receives keyboard messages before any child controls get the chance to see them. I have expanded the code above to be a complete working sample.
Tergiver
@Tergiver, I think this is "linq" base it is not useful in vs-2005 even i don't have any idea about linq language.
mahesh
@mahesh: This will work for .NET 2.0 (not Linq), but you need to get a newer version of Visual Studio to compile it.
Tergiver
@mahesh: I no longer have a copy of VS2005 as there is no need for it (I do have VS2003 for the extreme rare case where I need to work in .NET 1.1). I can no longer distinguish which language features are from which versions of the C# compiler. There is no good reason to use an older compiler that I can see. 2008 and 2010 are both capable of targetting .NET 2.0 but you can use the language features of C# 3 and 4 (at least those that don't require framework support--like Linq).
Tergiver
+1  A: 

Here is an alternate form using ProcessCmdKey on the form instead of using the custom DGV:

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

class Form1 : Form
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }

    DataGridView dgv;

    public Form1()
    {
        Text = "Form1";

        dgv = new DataGridView();
        dgv.Dock = DockStyle.Fill;
        DataGridViewComboBoxColumn dgvColumn = new DataGridViewComboBoxColumn();
        dgvColumn.HeaderText = "Header";
        dgvColumn.DataSource = new string[] { "One", "Two", "Three", "Four" };
        dgv.Columns.Add(dgvColumn);
        Controls.Add(dgv);

        Button button = new Button();
        button.Text = "Place holder";
        button.Dock = DockStyle.Top;
        Controls.Add(button);
    }

    [DllImport("user32.dll")]
    private static extern bool IsChild(IntPtr hwndParent, IntPtr hwndChild);

    protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
    {
        if ((keyData & (Keys.Alt | Keys.C)) == (Keys.Alt | Keys.C))
        {
            if (dgv.Handle == msg.HWnd || IsChild(dgv.Handle, msg.HWnd))
            {
                Form form = new Form();
                form.Text = "Form2";
                form.Show(this);
                return true;
            }
        }
        return base.ProcessCmdKey(ref msg, keyData);
    }
}
Tergiver
@Tergiver, did u test it.? it's giving compile error like " A New Express Requires() or [] after type
mahesh
@Tergiver, Note:- 4 compile error is there. same as i said above.
mahesh
@mahesh: Sounds like you're using an old C# compiler. Do yourself a favor and download a newer version of Visual Studio.
Tergiver
@Tergiver, Little help require for knowledge. see i have practice on vs-2005 since over a year and if i download the newer version than it should create the problem like new feature new linq language new component.etc.... Your help will turn me.
mahesh
@mahesh: You don't have to use a newer compiler to use ProcessCmdKey just like above. You just need to modify the code so that it compiles. I've modified both examples, but I cannot verify that they are C#2.0 compatible. I 'think' they are.
Tergiver
@Tergiver, You have did it. Well done. But still question in my mind that what is the connection of ProcessCmdKeys between RowHeaderVisible property set to true or false in DGV as above. Any way thanks it's finally solved and i accepted your answer.
mahesh
@mahesh: The problem lies in how the DGV uses a child control for the combo box. All of the key-related events are "top down". The event fires from the top-most control because of how OS messages interact with windows. ProcessCmdKey on the other hand works from the "bottom up". It gets to process the OS message *before* the target of that message sees it. Altering RowHeaderVisible simply changes the point at which the child combo box becomes active. The behavior (your event failing) is there with RowHeaderVisible set either way, you just have to change where you're focusing to see it.
Tergiver
@Tergiver,Thanks, Little information require. The problem we are discussing is solved in VS-2010. So i think in VS-2010 no need to override ProcessCmdKey. is it true?. As i have no Idea about it. if so then it's very easy to handle edited control what u think.
mahesh
@mahesh: I don't believe that it's solved by compiling with VS2010. Even if you change Framework versions as there have been no changes to WinForms since it was released in .NET 2.0.
Tergiver
@Tergiver, may be you are wright as i am not aware of VS-2010 but here is Henk Holterman comment that there is no effect on datagridview's rowheadervisible property setting by true or false on edited control
mahesh