bernova asked:
Dear Sergey, when I use just one of keypress function, that run correctly?
You don't understand.
There are no "keypress functions". There are events:
KeyPress
,
KeyDown
,
KeyUp
,
PreviewKeyDown
. Events can be handled by adding
your own methods to the invocation list of some event instances. Don't mix 3 things: 1) events as something which happens; 2) events as delegate types used in events; 2) events as instanced, members of some class invoking the event. Also, it's good not to mix up all these meanings of events with event handlers, which are delegate instances. Alternatively, you override the virtual methods such as
OnKeyPress
,
OnPreviewKeyDown
, and so on. These
On*
methods can be overridden to handle corresponding events (in the sense #1) without adding event handlers.
Please see:
https://msdn.microsoft.com/en-us/library/edzehd2t%28v=vs.110%29.aspx[
^],
https://msdn.microsoft.com/en-us/library/system.windows.forms.control_events%28v=vs.110%29.aspx[
^],
https://msdn.microsoft.com/en-us/library/system.windows.forms.control_methods%28v=vs.110%29.aspx[
^].
See also:
http://en.wikipedia.org/wiki/Object-oriented_programming[
^],
http://en.wikipedia.org/wiki/Virtual_function[
^],
http://en.wikipedia.org/wiki/Dynamic_dispatch[
^].
Even your whole idea "run correctly" is wrong. You should not try to "run correctly" or incorrectly anything, not yet. First, you need to understand what is "correctly", and a lot more: the idea of how things work. Unfortunately, right now you have no clue, and trial-and-error attempts cannot help you; and neither can help the "how to do it" recipes. You need to get the ideas.
[EDIT #1]
To achieve filtering of key press events, you could write
using System.Windows.Forms;
namespace MyProject
{
public partial class MyTextBox : TextBox {
protected override void OnKeyPress(KeyPressEventArgs e) {
e.Handled = !char.IsNumber(e.KeyChar);
if (e.KeyChar == (char)8)
e.Handled = false;
}
}
}
I answered to your code request, but I also need to explain the deal with 8: this is backspace which you need to allow.
Sorry that you are getting upset with my "you don't understand", but apparently you also don't quite understand how to work with Boolean expressions and "if".
Now,
this is not what you need.
DataGridView
is not a text box. You probably need to do the same for the text box which is the grid cell. You need to do it to the text box, not to the grid view itself.
This is how:
First of all, you need to handle the event
DataGridView.EditingControlShowing
:
public class MyDataGridView : DataGridView {
public MyDataGridView() {
this.EditingControlShowing += (sender, eventArgs) => {
if (eventArgs.Control.Tag == null)
eventArgs.Control.KeyPress +=
(editorSender, editorEventArgs) => {
bool isValid = char.IsDigit(editorEventArgs.KeyChar);
isValid != editorEventArgs.KeyChar == (char)8;
editorEventArgs.Handled = !isValid;
}
eventArgs.Control.Tag = true;
};
}
}
Can you see how tricky is that? You add and event handler each time the event
EditingControlShowing
is invoked; you add it to the editor you obtain from this first event. Then you handle each key press to filter out non-digit, but not backspace.
Also, this code is written in assumption that all your cells are of the type
System.Windows.Forms.DataGridViewTextBoxCell
. So you also need to excluded the cases when the control is of some different type. You can simply check up the
runtime type of the currently selected cell.
Please see:
https://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.editingcontrolshowing%28v=vs.110%29.aspx[
^],
https://msdn.microsoft.com/en-us/library/system.windows.forms.datagridvieweditingcontrolshowingeventargs%28v=vs.110%29.aspx[
^],
https://msdn.microsoft.com/en-us/library/system.windows.forms.datagridvieweditingcontrolshowingeventargs.control%28v=vs.110%29.aspx[
^].
[EDIT #2]
Sascha Lefèvre found a bug in my original code, a memory leak. Please see our discussion in comments.
I mistakenly assumed that new instance of the editor
eventArgs.Control
is created each time the editing is started.
Sascha checked up in the code sample he provided that the same instance of the editor is reused. I can confirm it; moreover, in the tests I executed, only one instance per
DataGridView
instance was created. Therefore, my code would add a new handler to the invocation list of the event instance
eventArgs.Control.KeyPress
again and again. After I realized that, I added a simple guard based on the
Tag
property which fixes the problem.
The leak problem is fixed; the correspondent lines are commented with "[EDIT #2]" in the code sample.
Note that this fix is reliable (FCL controls guarantee that this property is never touched by the libraries themselves) and is not making any assumptions on identities of the controls. The fix based on unsubscribed methods would be much more complicated, especially if it is made making no assumption on controls' identity. Such assumptions should not be made, because they are not documented, so the internal implementation of
DataGridView
could be changed at any version. Basically, it would require having an external collection of control instances ("subscribed controls"), and each subscription would need to check for the presence in the subscribed control collection.
Moreover, unsubscribe operation would (-=) require named, not anonymous methods, which is always worse; anonymous methods do not allow calling in any code except the '+=' operand, which provides better encapsulation.
One more issue would have to be resolved if you needed two or more "sorts of cells", with different character filtering rules. If this is the case, I would strongly recommend only one
KeyPress
handler working differently for different kinds of cells, through some "if" check
inside the handler.
—SA