Let's say my application consists of Rich Text Box and a button. I want the button to be enabled when users press a key in RTB, but it can't be any of modifiers.
I can handle this in some KeyEvent like PreviewKeyDown, but it doesn't work when I press modifier + other char, for instance SHIFT + S, which is valid, cause the result is letter S. Is there a way to separate my demand or should I make use of some different approach? I could use TextChanged, but there are many more actions that I've already written and I would prefer to do it that way.
Simple explanation:
private void richTextBox_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
if (!e.Alt && !e.Control && !e.Shift)
{
this.button1.Enabled = true;
else
this.button1.Enabled = false;
}
}
Since the KeyPress event Occurs when a character, space or backspace key is pressed while the control has focus and modifier keys has no impact on this event, it seems using KeyPress may help you.
But you better consider handling TextChangedevent and checking TextLength, since the user can paste something in the RichtextBox, and this way none of key events will fire.
Related
I am currently working on a calculator application that looks similar to what the Windows 10 standard calculator looks like. I am practically done with it but sort of ran into an issue I thought I could fix but can't seem to figure out.
I envisioned the calculator being able to have input pressed from on the screen like pressing the "1" button "+" button etc, while also having input from the keyboard. I figured out how to have it sort of work but I have to click the button so the focus shifts to that button every time.
Is there a way to bypass the focus and just look for which button is pressed? I have looked on other posts from this website but haven't found one that seems to match my needs.
Here is my code so far,
private void oneBtn_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.D1 || e.KeyChar == (char)Keys.NumPad1)
{
textBox1.Text = textBox1.Text + "1";
}
}
Would I have to set the focus to the whole page in order to achieve what I want my application to do? Is there even a way to do this? I found an question on reddit that seemed pretty similar to what I am asking and it mentions setting the "KeyPreview" property to true. I have done this here,
public CalculatorPage()
{
InitializeComponent();
this.KeyPreview = true;
}
but I am still not getting the button click from other buttons to work because the focus is still on the "1" key from loading the program up.
you should handle the key binding in the Form Key press event, something like this
private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
// NUM PAD 1
if (e.KeyChar == (char)Keys.D1 || e.KeyChar == (char)Keys.NumPad1)
{
textBox1.Text = textBox1.Text + "1";
}
// CHAR NUM PAD 2
...
// CHAR NUM PAD 3
...
}
The way I understand it, you want to make the button which you pressed in the previous "round" of calculating lose the focus the next time the calculator is opened.
You could do that just by either coding it, e.g. Btn_example.CanFocus = false or you could click every button you want no focus in the Designer and under Properties (bottom left corner) set the CanFocus property to false
I was originally trying to get my program to get inputs of the arrow keys (Up, Down, Left and Right), but found out the hard way that in KeyDown(), those keys never made. Afterwards I found out that I could enable the arrow keys by going into the PreviewKeyDown() function and setting:
e.IsInputKey = true;
with whatever conditionals and logic around it. The trouble was that when I wrote the function:
private void Form1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{ /*whatever logic goes here*/}
it never fired; I even set a breakpoint that would trigger inside the function to be sure. Also, I tried:
this.Focus()
in the constructor to make sure that the main form had the focus, but it made no difference. The only thing that worked was setting the focus to a Button I had created and the button also trigger on a PreviewKeyDown event by calling the above Form1_PreviewKeyDown().
So at this point I have a working method, but can anyone help me understand why it never originally fired? I'm assuming that for some reason the Form's PreviewKeyEvent never fires, but I really have no idea why.
Why
You can try this little experiment: Make a form with two buttons, override PreviewKeyDown(), set a breakpoint, run it, and press the left/right arrow keys. The PreviewKeyDown() method won't be run. But delete the buttons and the override will be called.
The reason for the difference is that WinForms is handling the arrow keys itself for navigation. When you have input controls like buttons and text boxes, WinForms will automatically take over certain special keys like TAB and the arrow keys to navigate from one control to the next. It probably does this because a lot of people like to be able to use the keyboard to navigate, and it's easy to break that for them if you go messing with the navigation keys. Better to handle them for you so you don't mess them up by accident while you're playing with the other keys.
A naive workaround would be to detect when you form loses focus and take it back. This doesn't work though, because your form doesn't lose focus. The input controls have the focus, and they're part of the form, so the form still (technically, indirectly) has focus. It only loses the focus when you click outside on some other window.
A better workaround involves a better understanding of what's going on "under the covers", just below the .Net interpreter. WinForms mimics this level fairly closely, so it's a useful guide to understanding what WinForms is up to.
When Windows sends input (like keystrokes) to your program, your form isn't always the first to get the input. The input goes to whichever control has the focus. In this case, that control is one of the buttons (I'm assuming the focus glow is hidden at first to justify why nothing happens on the first stroke when nothing looks selected).
Once the button gets hold of the input, it gets to decide what happens next. It can pass the input on to whoever's next in line, do something and then pass it on, or completely handle the input and not pass it on at all.
With normal letter keys, the button decides it doesn't know what to do with them and passes them to its base class instead. The base class doesn't know either, so it forwards the key on. Eventually, it hits the Control class, which handles it by passing it on to whichever Control is in its Parent property. If that goes on long enough, your form will eventually get a chance to handle the input.
So in a nutshell, WinForms is giving the input to the most specific target first, then working out to more and more general things until someone knows how to handle the input.
In the case of the arrow keys, however, the button knows how to handle those. It handles them by passing the focus on to the next input control. At that point, the button declares the input totally handled, swallows the key and doesn't give anyone else a chance to look at it. Nobody after the button even knows the keystroke ever happened.
That's why your PreviewKeyDown() override isn't being called. It's only called when your Form gets a keystroke, but it never gets the keystroke because it went to an input control, the input control offered to let the navigation code look at it, and the navigation code swallowed it.
Workaround
Unfortunately, getting around this is going to be some work. The keystrokes are disappearing into the input controls, so you'll need to get all the input controls involved in getting the arrow keys into your form.
To do this, you'll need to derive new controls from all the input control types you use and use them in place of the originals. Then you'll have to override the OnPreviewKeyDown() method in each one and set e.IsInputKey = true. That'll get your arrow keys into the derived controls' KeyDown() handlers instead of having them stolen by the navigation code.
Next, you'll have to handle the KeyDown() event in all those controls, too. Since you want the arrow keys to raise events in the Form, all the derived controls will need to track down their form and pass the keys to that (which means the form's method will need to be public).
Putting all that together, the arrow-key-passing input controls will look about like this.
class MyButton : Button
{
public MyButton()
{
this.KeyDown += new KeyEventHandler(MyButton_KeyDown);
}
protected override void OnPreviewKeyDown(PreviewKeyDownEventArgs e)
{
e.IsInputKey = true;
base.OnPreviewKeyDown(e);
}
private void MyButton_KeyDown(object sender, KeyEventArgs e)
{
Form1 f = (Form1)this.FindForm();
f.Form1_KeyDown(sender, e);
}
}
That's going to be a bit error prone with all the repeated code.
An easier way would be to override your form's ProcessCmdKey() method and handle the keys there. Something like this would probably work:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Up || keyData == Keys.Down ||
keyData == Keys.Left || keyData == Keys.Right)
{
object sender = Control.FromHandle(msg.HWnd);
KeyEventArgs e = new KeyEventArgs(keyData);
Form1_KeyPress(sender, e);
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
This effectively steals the command keys (those special navigation keys) even before the input controls get a chance at them. Unless those controls override PreviewKeyDown() and set e.IsInputKey = true. The child's PreviewKeyDown() method will come first, then the arrow will be considered not a command key and your ProcessCmdKey() won't be called.
ProcessCmdKey() is meant for context menu handling. I'm not sure whether it's wise to go using it for things other than context menus, but even Microsoft recommends it for similar kinds of use and it does seem to work, so it may be worth considering.
Conclusion
Long story short, navigation keys are meant for navigation. Messing with them can make the user experience unpleasant for keyboard users, so .Net makes it hard to get at them so you'll be encouraged to mess with other keys instead.
I had the same problem!
Luckily i found a dense answer :)
you can use the bool function in the definition of the Form class witch occurs on every key pressed. but remember to return the base function!
public partial class myForm : Form
{
public myForm ()
{
InitializeComponent();
}
protected override bool ProcessDialogKey(Keys keyData)
{
//Add your code here
return base.ProcessDialogKey(keyData);
}
}
hopefully i helped. but if my answer is incomplete please note me!
Keyboard events on the parent form are pretty useless unless you also set
this.KeyPreview = true;
see the MSDN documentation
I have textboxes in my Windows Forms application, and I want that when the user presses the ENTER key then the cursor goes to the next textbox.
How do I do this?
Is this a good habit or shall I avoid it? Actually the users are very much prone and have adapted and have become habitual of pressing ENTER key for navigation between textboxes and buttons. So, for them I need to do this.
Please help me with the complete code using two text-boxes as an example.
I would say the nicest way is to create a user control that inherits from TextBox and then override the OnKeyPress method to capture enter and send a tab. Focus will then be given to the next TabIndex on the form, just as though a tab had actually been entered.
The code below does exactly that:
public partial class CustomTextbox : TextBox
{
public CustomTextbox()
{
InitializeComponent();
}
protected override void OnKeyPress(KeyPressEventArgs e)
{
if (e.KeyChar == '\r')
{
e.Handled = true;
SendKeys.Send("{TAB}");
}
}
}
You could also put similar code in the KeyPress event handlers for your controls but this saves a lot of duplicate code and unnececessary event handler.
As for whether this is good practice - I would say in general, no, changing the default behaviour of forms is never a good idea, but of course, if this is what your users want and expect, then it is their decision.
This is a bad idea. The standard UI is for TAB to move between input fields. You make your app less useable when you elect not to follow well known standards. These standards are what makes UI intuitive.
Yes, it depends on you
For a sample, you can place 4 textbox on the form and use the following code
private void textBox1_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
textBox2.Focus();
}
}
private void textBox2_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
textBox3.Focus();
}
}
private void textBox3_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
textBox4.Focus();
}
}
It might help you.
Happy coding...
For example you could trap OnKeyUp event, check if it is RETURN and process source control to use Focus() to next control...
Yes you can fire the KeyDown or KeyUp event on a TextBox. To check whether it was the enter key, you can do the following:
//e is the KeyEventArgs from the event.
e.KeyCode == Keys.Enter
Then, if he has pressed the enter key, you can do:
System.Windows.Forms.Control.SelectNextControl();
To set the order of your controls, in Visual Studio look for this little icon:
http://i.stack.imgur.com/nZWLO.png
Click it, and you'll go into tab ordering mode, as I like to call it. Just click the controls in the order you wish them to be and after you're done, click the little icon again. Presto!
Now whether that is a good idea of not, completely depends on how used to it your end users are. If they have always used it like this, and you give them something that doesn't fit into their mind model, they are going to say your software is broken.
Always always always try to emulate what processes the user already has in place in their head.
Read this if you have the time, it's a really light and very good read:
http://www.joelonsoftware.com/uibook/fog0000000249.html
I think the best way would be to:
1) assign each textbox's TabIndex attribute incrementally (first is x, next is x+1 etc).
2) capture on the OnKeyUp event on the whole form, check the argument to see if the key was RETURN
3) focus the next textbox using its TabIndex. Or simulate the TAB key.
This code should work:
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
GetNextControl((TextBox)sender, true);
}
}
This way you end up writing only one function, and you can have as many textboxes as you want.
I'm running into a very peculiar issue. I noticed that occasionally while typing into my TextBox, I'll lose some keystrokes. I added a bunch of trace statements in events hooked by this TextBox, and I found that when I lost keystrokes, the KeyUp, KeyDown, and KeyPress events all correctly fired, but the TextChanged event never fired.
Does anybody have any idea why this would happen? I could write this off as a ".NET bug", but I'd rather figure out if there is a solution here.
In case there is a suggestion that I use the KeyUp/KeyDown events to determine if the text has changed, there is an issue there as well. KeyUp/KeyDown are called multiple times for each key press, so it would be very difficult to determine if someone was typing the same letter multiple times.
Hmmm....
This is going to be a shot, but, you did say you have the KeyUp, KeyDown and KeyPress event handlers right? Have you set the flag e.Handled to true in the event handlers, have a look here:
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
e.Handled = true;
}
private void textBox1_KeyUp(object sender, KeyEventArgs e)
{
e.Handled = true;
}
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = true;
}
Have a look here in the MSDN about this Handled property. (If you have MSDN 2008 SP 1 installed locally, the link is ms-help://MS.MSDNQTR.v90.en/fxref_system.windows.forms/html/dfc80b44-1d79-6315-cbea-1388a048c018.htm)
To quote:
Handled is implemented differently by different controls within Windows Forms.
For controls like TextBox which subclass native Win32 controls, it is
interpreted to mean that the key message should not be passed to the underlying
native control.
If you set Handled to true on a TextBox, that control will not pass the key
press events to the underlying Win32 text box control, but it will still
display the characters that the user typed.
Maybe it is not set i.e. e.Handled = false; thereby preventing the TextChanged Event from firing?
Can you check and confirm this?
Edit: After dreadprivateryan's response, I can suspect (due to lack of code posted), based on his response, e.Handled is true for when Enter key is pressed and false for everything else which in my mind, thinks that is the reason why no further keystrokes are being accepted as a result of this.
Are you trying to set focus to another control upon the Enter key being pressed? It could be that both KeyUp and KeyDown are conflicting...
Remove the keyboard hook and disable it...
My suggestion is to change the code completely in this manner as shown, take out either KeyDown or KeyUp Event Handler as they, simplistically put it, are the same, ok, technically, it is designated respectively for when a key is pressed down, and likewise when a key is released. Have a look at this link here. There was a similar question posted here on SO.
In the example below, I used the keyUp event handler to switch focus to the next available control upon enter key being pressed. In the KeyPress event handler, this simply filters the input and only allows numbers 0-9 respectively, anything else gets discarded. Included in that event handler, is the allowance for the backspace key to provide editing.
private void textBox1_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter) SendKeys.Send("{TAB}");
}
private const string VALID_KEYS = "0123456789";
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if (VALID_KEYS.IndexOf(char.ToUpper(e.KeyChar)) != -1 || e.KeyChar == (char)8)
e.Handled = false;
else
e.Handled = true;
}
Hope this helps,
Best regards,
Tom.
I don't actually know, but I have a random guess: You running in a VM?
One hack you could use is make a timer that reads the text and compares to the previously entered value. Call the event handler code when it isn't equal to the previously checked value. When you need to use the final entered value, do one additional check, in case the timer hasn't fired yet.
Do you mean the keypress is actually lost and never shows up in the box? Or do you mean you don't get a TextChanged event for every keypress?
I believe the TextChanged event is driven by the operating system's EN_CHANGE notification which is sent via a WM_COMMAND message. I know that certain kinds of messages in Windows are "coalesced" to avoid redundant notifications. For example this can happen with WM_MOUSEMOVE messages and is why you don't receive a mouse move event for every pixel that the mouse moves across the screen.
I can't say for sure but I suspect that the TextChanged event behaves this way as well. I can say though that alternate input methods have this side effect too. When using a Tablet PC input panel, the textbox will not get a TextChanged notification for every character.
I want to activate a search textbox when the user starts to type something (even if the textbox isnt focused right then). I have come as far as setting KeyPreview on the form to true. Then in the KeyDown event handler, I have this:
if(!searchTextBox.Focused)
{
searchTextBox.Focus();
}
This almost works. The textbox is focused, but the first typed letter is lost. I guess this is because the textbox never really gets the event, since it wasn't focused when it happend. So, do anyone have a clever solution to how I could make this work like it should?
I would also like some tips to how make this only happen when regular keys are pressed. So not like, arrow keys, modifier keys, function keys, etc. But this I will probably figure out a way to do. The previous issue on the other hand, I am not so sure how I should tackle...
As an addition to the answer from SDX2000, have a look at the MSDN article for the KeyDown event. It also refers to the KeyPressed event, which is fired after the KeyDown event, I think it is better suited for what you want to do.
Quoting MSDN:
A KeyPressEventArgs specifies the character that is composed when the user presses a key. For example, when the user presses SHIFT + K, the KeyChar property returns an uppercase K.
private void YourEventHandler(object Sender, KeyPressEventArgs Args)
{
if(!searchTextBox.Focused)
{
searchTextBox.Focus();
searchTextBox.Text += Args.KeyChar;
// move caret to end of text because Focus() selects all the text
searchTextBox.SelectionStart = searchTextBox.Text.Length
}
}
I'm actually not certain that you can use += to append a char to a string, so you need to check on that. And I don't know what happens when the user hits return, better follow up an that issue as well.
You will get the first key stroke as part of the KeyDown event. You can save it to the textbox yourself.