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

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

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

Я старался

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

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

Вот мой метод, чтобы найти ENTER, находясь в редактировании

Добавление события

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() но последний "ввод" будет последним в представлении.

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

10 ответов

Решение

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

То, что я закончил, чтобы "отменить" событие клавиши ввода при редактировании ячейки, чтобы использовать смесь 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 из элемента управления редактирования.

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

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

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

Таким образом, вместо того, чтобы послать ключ ввода, он эмулирует действие для 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

Это просто обходной путь, а не реальное решение, но оно работает.

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

Но у меня была точно такая же проблема, и я не хотел кэшировать строки и т. Д. Так что я погуглил, и это мое решение вопроса. Кредиты на Как предотвратить нажатие клавиши 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

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

1... Создайте событие KeyDown для этого вида сетки (перейдите к свойствам в виде сетки и дважды щелкните событие 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. Запустите программу и посмотрите.

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

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, добавил мои столбцы и обработал ключ ввода из 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);
    }
}

Просто сделай так, чтобы все заработало.

private void dataGridViewX1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
    {

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

Единственный способ, которым я нашел это, — создать собственный DataGridView.

Изменить: это изменит поведение клавиш со стрелками по умолчанию и позволит использовать клавиши со стрелками при редактировании. Вы можете изменить это, удалив «e.KeyCode == Keys.Left || e.KeyCode == Keys.Right».

          public class CustomDataGridview : DataGridView
    {
        protected override bool ProcessDataGridViewKey(KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Left || e.KeyCode == Keys.Right)
            {
                return false;
                //if (IsCurrentCellInEditMode)   // disable the keys only in EditMode
                //{
                //    return false;
                //}
            }
            return base.ProcessDataGridViewKey(e);
        }

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

    CustomDataGridview dgvCustom = new CustomDataGridview();
    DataGridViewTextBoxColumn InputFile2 = new DataGridViewTextBoxColumn();
    DataGridViewTextBoxColumn OutputFile2 = new DataGridViewTextBoxColumn();
    DataGridViewComboBoxColumn Format2 = new DataGridViewComboBoxColumn();
    DataGridViewTextBoxColumn Options2 = new DataGridViewTextBoxColumn();

    private void SetupDataGridView()
    {
        //All your DataGridView settings
    }

    public Form1()
    {
        InitializeComponent();
        SetupDataGridView();
    }

На основе этого решения я создал свой собственный. Вам не нужно перехватывать KeyDown_Event в DataGrid для Enter_key, а скорее переключать свойство AllowUserToAddRows . В моем случае я выбрал CellContentDoubleClick для его включения:

      private void myDataGrid_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e) {
    myDataGrid.AllowUserToAddRows = false;
}

private void myDataGrid_CellContentDoubleClick(object sender, DataGridViewCellEventArgs e) {
    myDataGrid.AllowUserToAddRows = true;
}

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

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);
    }      
}
Другие вопросы по тегам