Как предотвратить переход к следующей строке после редактирования DataGridViewTextBoxColumn и нажатия клавиши Enter?

я работаю над программой с DataGridViews. В одном DatagridView есть DataGridViewTextBoxColumn, который включен для редактирования пользователем. Когда пользователь закончит вводить в него цифры, он нажимает ENTER на клавиатуре. Теперь DataGridView все свои Events, и после Events, последнее, в чем проблема.

все сделано, и Windows собирается выбрать следующий DataGridViewRow, и я не могу предотвратить это.

я попытался

if (e.KeyData == Keys.Enter) e.SuppressKeyPress = true; // or e.Handled 

почти во всех случаях, которые я нашел. К сожалению, я смог предотвратить ввод ключа только тогда, когда DataGridViewTextBoxColumn не находится в режиме редактирования.

Heres мой methode t найти ввод во время редактирования

добавить событие

private void dgr_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
    e.Control.KeyPress += new KeyPressEventHandler(dgr_KeyPress_NumericTester);
}

и это событие для приема только числового ввода.

private void dgr_KeyPress_NumericTester(object sender, KeyPressEventArgs e)
{
    if (!Char.IsDigit(e.KeyChar) && e.KeyChar != 8) e.Handled = true;
}

подробно объяснить:

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

я также пробовал это с DependingControl.Focus() но последнее "enter" будет последним в представлении.

кто-нибудь знает, как предотвратить это?

8 ответов


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

что я закончил ,чтобы "отменить" ключевое событие enter при редактировании ячейки, чтобы использовать смесь CellEndEdit событие и SelectionChanged событие.

Я представил пару полей уровня класса, которые хранят некоторое состояние - в частности, в какой строке мы находимся в конце редактирования ячейка и ли мы останавливаем выбор изменены.

код выглядит так:

public partial class Form1 : Form
{
    private int currentRow;
    private bool resetRow = false;

    public Form1()
    {
        InitializeComponent();

        // deleted out all the binding code of the grid to focus on the interesting stuff

        dataGridView1.CellEndEdit += new DataGridViewCellEventHandler(dataGridView1_CellEndEdit);

        // Use the DataBindingComplete event to attack the SelectionChanged, 
        // avoiding infinite loops and other nastiness.
        dataGridView1.DataBindingComplete += new DataGridViewBindingCompleteEventHandler(dataGridView1_DataBindingComplete);
    }

    void dataGridView1_SelectionChanged(object sender, EventArgs e)
    {
        if (resetRow)
        {
            resetRow = false;
            dataGridView1.CurrentCell = dataGridView1.Rows[currentRow].Cells[0];          
        }
    }

    void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
    {
        resetRow = true;
        currentRow = e.RowIndex;
    }

    void dataGridView1_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
    {
        dataGridView1.SelectionChanged += new EventHandler(dataGridView1_SelectionChanged);
    }
} 

вы хотите, чтобы проверить это тщательно, чтобы убедиться, что это именно то, что вам нужно. Я только проверил, что он останавливает изменение строки при нажатии enter из элемента управления редактирования.

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


я попробовал это для изменения поведения ввода для вашей сетки путем наследования customcolumn от Столбец Textbox и переопределение события

protected override bool ProcessDialogKey(Keys keyData)
{
    if (keyData == Keys.Enter)
       return base.ProcessDialogKey(Keys.Tab);
    else
       return base.ProcessDialogKey(keyData);
}

поэтому вместо отправляемого ключа Enter он эмулирует действие для Tab, которое будет перемещаться в следующую ячейку. Надеюсь, это поможет


Private Sub DataGridView1_KeyDown(sender As Object, e As KeyEventArgs) Handles DataGridView1.KeyDown
    If e.KeyData = Keys.Enter Then e.Handled = True
End Sub

Это просто временное решение, а не реальное решение, но оно работает.


Я знаю, что этот вопрос был задан давно, но ответ может быть полезен для тех, кто ищет в будущем, я надеюсь. лучшее решение-использовать пользовательский столбец и для textbox его легко, потому что мы будем использовать встроенные классы

class Native
{
    public const uint WM_KEYDOWN = 0x100;
    [DllImport("user32.dll")]
    public static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, Int32 wParam, Int32 lParam);
}
//the column that will be added to dgv
public class CustomTextBoxColumn : DataGridViewColumn
{
    public CustomTextBoxColumn() : base(new CustomTextCell()) { }
    public override DataGridViewCell CellTemplate
    {
        get { return base.CellTemplate; }
        set
        {
            if (value != null && !value.GetType().IsAssignableFrom(typeof(CustomTextCell)))
            {
                throw new InvalidCastException("Must be a CustomTextCell");
            }
            base.CellTemplate = value;
        }
    }
}
//the cell used in the previous column
public class CustomTextCell : DataGridViewTextBoxCell
{
    public override Type EditType
    {
        get { return typeof(CustomTextBoxEditingControl); }
    }
}
//the edit control that will take data from user
public class CustomTextBoxEditingControl : DataGridViewTextBoxEditingControl
{
    protected override void WndProc(ref Message m)
    {
        //we need to handle the keydown event
        if (m.Msg == Native.WM_KEYDOWN)
        {
            if((ModifierKeys&Keys.Shift)==0)//make sure that user isn't entering new line in case of warping is set to true
            {
                Keys key=(Keys)m.WParam;
                if (key == Keys.Enter)
                {
                    if (this.EditingControlDataGridView != null)
                    {
                        if(this.EditingControlDataGridView.IsHandleCreated)
                        {
                            //sent message to parent dvg
                            Native.PostMessage(this.EditingControlDataGridView.Handle, (uint)m.Msg, m.WParam.ToInt32(), m.LParam.ToInt32());
                            m.Result = IntPtr.Zero;
                        }
                        return;
                    }
                }
            }
        }
        base.WndProc(ref m);
    }
}

затем мы приходим к самому dgv я использовал новый класс, производный от DataGridView и добавил мои столбцы и обработал ключ enter из wndproc также

void Initialize()
{
    CustomTextBoxColumn colText = new CustomTextBoxColumn();
    colText.DataPropertyName = colText.Name = columnTextName;
    colText.HeaderText = columnTextAlias;
    colText.DefaultCellStyle.WrapMode = DataGridViewTriState.True;
    this.Columns.Add(colText);
    DataGridViewTextBoxColumn colText2 = new DataGridViewTextBoxColumn();
    colText2.DataPropertyName = colText2.Name = columnText2Name;
    colText2.HeaderText = columnText2Alias;
    colText2.DefaultCellStyle.WrapMode = DataGridViewTriState.False;
    this.Columns.Add(colText2);
}
protected override void WndProc(ref Message m)
{
    //the enter key is sent by edit control
    if (m.Msg == Native.WM_KEYDOWN)
    {
        if ((ModifierKeys & Keys.Shift) == 0)
        {
            Keys key = (Keys)m.WParam;
            if (key == Keys.Enter)
            {
                MoveToNextCell();
                m.Result = IntPtr.Zero;
                return;
            }
        }
    }

    base.WndProc(ref m);
}

//move the focus to the next cell in same row or to the first cell in next row then begin editing
public void MoveToNextCell()
{
    int CurrentColumn, CurrentRow;
    CurrentColumn = this.CurrentCell.ColumnIndex;
    CurrentRow = this.CurrentCell.RowIndex;
    if (CurrentColumn == this.Columns.Count - 1 && CurrentRow != this.Rows.Count - 1)
    {
        this.CurrentCell = Rows[CurrentRow + 1].Cells[1];//0 index is for No and readonly
        this.BeginEdit(false);
    }
    else if(CurrentRow != this.Rows.Count - 1)
    {
        base.ProcessDataGridViewKey(new KeyEventArgs(Keys.Tab));
        this.BeginEdit(false);
    }
}

вы можете сделать это просто....

1...Создайте событие KeyDown для этого представления сетки.(Перейдите к свойствам в gridview и дважды щелкните событие KeyDown).

2...Мимо этого кода -

if(e.KeyData == Keys.Enter)
{
  e.Handled = true;
}

3...Наконец - то это выглядит так.

private void dgvSearchResults_KeyDown(object sender, KeyEventArgs e)
{
  if (e.KeyData == Keys.Enter)
   {
    e.Handled = true;
   }
}

4..Запустите программу и посмотрите.


этот ответ действительно приходит поздно...

но у меня была такая же проблема, и я не хотел кэшировать строки и т. д. Поэтому я погуглил, и это мое решение вопроса. Кредиты как предотвратить нажатие клавиши Enter от завершения EditMode в DataGridView?

наследовать от DataGridView и добавить этот код (vb.net):

Protected Overrides Function ProcessCmdKey(ByRef msg As Message, keyData As Keys) As Boolean
    If Commons.Options.RowWiseNavigation AndAlso Me.IsCurrentCellInEditMode AndAlso (keyData = Keys.Enter Or keyData = Keys.Tab) Then
        ' End EditMode, then raise event, so the standard-handler can run and the refocus is being done
        Me.EndEdit()
        OnKeyDown(New KeyEventArgs(keyData))
        Return True
    End If

    'Default
    Return MyBase.ProcessCmdKey(msg, keyData)
End Function

просто сделайте так, чтобы он работал нормально.

private void dataGridViewX1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
    {

        SendKeys.Send("{UP}");
        SendKeys.Send("{Right}");
    }

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

public class DataGridViewNoEnter : DataGridView
{       
    protected override bool ProcessDataGridViewKey(KeyEventArgs e)
    {
        if (e.KeyCode == Keys.Enter)
        {
            ((Form)this.TopLevelControl).DialogResult = DialogResult.OK;
            return false;
        }
        return base.ProcessDataGridViewKey(e);
    }      
}