0

I'm trying to figure out how to edit a datagridview cell where it behaves like a regular textbox. Currently when I click the cell the cursor is placed at the beginning of text with:

dgvVX130.BeginEdit(false);
((TextBox)dgvVX130.EditingControl).SelectionStart = 0;  

I can then edit with keys and can move cursor position with left and right arrows.

Also I would like to be able to select a portion of text within the cell which I would then copy or delete. Currently mouse selection appears to be totally inoperable.

How can I can change cursor position with mouse also? How can I select a portion of text with mouse?

artm
  • 8,554
  • 3
  • 26
  • 43
Thom Ash
  • 221
  • 4
  • 20
  • Hi! Did you see this https://social.msdn.microsoft.com/Forums/en-US/04362a62-8cbf-4d86-a1bc-2aba8e4978ca/cursor-position-in-textbox?forum=Vsexpressvcs ? – Ilia Maskov Apr 17 '15 at 14:18
  • This is helpful. Now I know difference between caret and cursor. So my question is really the interaction of both. Currently I'm setting caret with selectionStart so now I need to detect the position of mouse cursor on click and set selectionstart. I then need to detect length of mouse drag and set selectionlength. I guess I need to find that information cursor position and mouse drag. – Thom Ash Apr 17 '15 at 14:31
  • After casting to TextBox you may succeed using `Textbox.GetCharFromPosition(mouseLocation)`. I think keeping a reference to the TextBox will make things easier.. – TaW Apr 17 '15 at 15:43
  • I've tried that and index but without success. var pos = Cursor.Position; var num = ((TextBox)dgvVX130.EditingControl).GetCharIndexFromPosition(pos); var numz = ((TextBox)dgvVX130.EditingControl).GetCharFromPosition(pos); For example num doesn't change when click begin and then end of string. I'm not holding my jaw right or something. – Thom Ash Apr 17 '15 at 16:23

1 Answers1

2

Maybe this first example will help. It selects 3 characters from the clicked mouse position when entering the cell edit mode:

private void dataGridView1_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
    if (dataGridView1.EditingControl == null)
    {
        dataGridView1.BeginEdit(false);
        TextBox editor = (TextBox)dataGridView1.EditingControl;
        // insert checks for null here if needed!!
        int ms = editor.GetCharIndexFromPosition(e.Location);
        editor.SelectionStart = ms;
        editor.SelectionLength = Math.Min(3, editor.Text.Length - editor.SelectionStart);
    }
}

Note that the code only executes when we are not in edit mode already! This is probably where your code fails..

Update: As you seem to want the option of the user to start both edit mode and setting a selection at the first mouse down, here is a piece of code that does just that for me.

It uses a little Lambda for both the TextBox edit control and a temporary Timer but could just as well be written without the Lambda.. The Timer is needed as the MouseDown event keeps the mouse captured until the event is done even after releasing the Capture, thereby preventing the cell from entering edit mode..

Note that all further error checking is left to you, especially for the editor control, which will be null for protected cells and for non-text cells..

int mDwnChar = -1;
DataGridViewCell lastCell = null;

private void dataGridView1_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
{
    DataGridViewCell cell = dataGridView1[e.ColumnIndex, e.RowIndex];
    if (dataGridView1.EditingControl == null || cell != lastCell)
    {
        dataGridView1.BeginEdit(false);
        TextBox editor = (TextBox)dataGridView1.EditingControl;
        editor.MouseMove += (ts, te) =>
        {
            if (mDwnChar < 0) return;
            int ms = editor.GetCharIndexFromPosition(te.Location);
            if (ms >= 0 && mDwnChar >=0)
            {
               editor.SelectionStart = Math.Min(mDwnChar, ms);
               editor.SelectionLength = Math.Abs(mDwnChar - ms + 1); 
            }
        };
        editor.MouseUp += (ts, te) => { mDwnChar = -1; };

        mDwnChar = editor.GetCharIndexFromPosition(e.Location);
        dataGridView1.Capture = false;
        Timer timer00 = new Timer();
        timer00.Interval = 20;
        timer00.Tick += (ts, te) => { 
            timer00.Stop();
            dataGridView1.BeginEdit(false);
        };
        timer00.Start();

        lastCell = cell;
    }
}
TaW
  • 53,122
  • 8
  • 69
  • 111
  • Thanks for the example. I tried it and it does grab the first 3 characters from mouse click position as you prepare to enter edit mode but that's not exactly what I'm trying to do. Yes this may be useful for getting start but I need to get an end based on mouse movement as well and not a static 3 characters. I also encountered some negative blowback with the mouseclick event instead of CellContentClick event I'm using currently but CellContentClick doesn't have the Location argument. – Thom Ash Apr 18 '15 at 00:23
  • Ah, I'll try to update my answer later, but atm I'm still sleeping ;-) But first let's get clear about the order of events you want: 1) __After a Click__ in the cell it should go into edit mode. 2) __While moving__ around in it the selection should change accordingly. 3) __When should it__ be fixed again? __After__ a 2nd Click? When __leaving__ the cell? – TaW Apr 18 '15 at 01:08
  • See my pdated answer; note that CellContentClick would only start after the mouseup, which imo makes for a rather poor user experience.. – TaW Apr 18 '15 at 06:33
  • See my updated answer; note that `CellContentClick` (as it is a `Click` )would only start after the mouse is up, which imo makes for a rather poor user experience.. – TaW Apr 18 '15 at 06:48
  • Thank you. I'll give this a try. To answer your question, I would like the DataGridView Textbox to behave the same as a regular Textbox in regard to data selection as well as cut, copy, and paste. Use of CellContentClick was arbitrary at first but it works properly with a ClipboardUtil Class. I have a context menu that I use to copy and paste on right click. The MouseClickEvent didn't paste correctly for some reason. I'll see how the interaction goes with CellMouseDown. – Thom Ash Apr 18 '15 at 13:29
  • So I worked with this, and thanks for your efforts, but it's just to kludgy for production use. Users are accustomed to working with windows applications like Excel and SQL Server. It's a shame Microsoft didn't do a better design job. – Thom Ash Apr 22 '15 at 18:01
  • Thanks for the brilliant code and info. When I tried the first code, I noticed that when you click after the last character in the cell, the mouse pointer jumps back before the last character. Strange! – NoChance Jan 08 '22 at 20:30