So, here's the deal. What I wanna do must be really simple, but I just can't find a solution that doesn't involve building a few classes and it wouldn't even be worth my trouble.
In a regular TextBox there is the OnKeyUp event. It's handler signature demands the sending object (of course) and a KeyEventArgs object. All I want is replace this KeyEventArgs with a CancelEventArgs object. Or, not even that, let's say that I just wanna add a new CancelEventArgs parameter to the handler. In other words, all I want is that if the wrong key is pressed, the whole event is cancelled.
I see there's a topic with a seemingly similar question, but that won't do.
Any pointers?
Set the SuppressKeyPress property of the KeyEventArgs object of the KeyDown event to true to prevent user input.
No, you can't add an extra parameter to an existing event handler. After all, the TextBox is going to raise that event - how would it know what to do for your extra parameter, or even your different one? It's been told that it will be given a KeyEventHandler to call, so it believes it can call that event handler with the normal arguments.
How would you expect this to work from the point of view of the TextBox?
As SemVanmeenen suggests, you may well find that SuppressKeyPress is what you want, although that's not quite the same as "cancelling" the whole event. It's worth making sure you understand why you can't change event handler parameters though.
If the above doesn't help, you might want to read my article on events and delegates for a better feel for how they work.
Related
I have a uwp app with some global keypress handling. I do it by subscribing to two different sets of events:
CoreWindow.CharacterReceived (for text keypresses), and
MainPage.KeyDown (for escape, arrow keys, enter, etc.)
But my app also has some TextBoxes. When one of those has focus, I want to disable the above in almost all cases. (arrow keys and tab are sometimes exceptions).
I could certainly do that by overriding OnGotFocus and OnLostFocus in my TextBox wrapper objects and keeping track of whether or not a TextBox currently has focus.
Is there a better way?
EDIT: I've found FocusManager.GetFocusedElement(). This is an improvement, but still does not feel ideal.
Maybe you can use the FocusManager.GetFocusedElement() and check whether the returned element is of type TextBox. So you should add something like this to your CoreWindow.CharacterReceived and MainPage.KeyDown event handlers:
EventHandler(parameters)
{
if (FocusManager.GetFocusedElement() is TextBox)
{
return;
}
// event handling
}
that is a question I have been asking myself for a while.
Giving a certain flow of events, can I when handling one of them, stop the next ones to be raised?
For example, when collapsing a node which child was selected in a treeview (winform), the events are raised like that:
BeforeCollapse
BeforeSelect
AfterSelect
AfterCollapse
I could stop them by using a class member, but I was wondering whether there was a built-in function or just another way (a more elegant way) to achieve this, by acting directly on the events queue.
Any idea?
Not easily, no. The order of the events firing is controlled by the TreeView control class, and there is no built-in way to prevent events from firing. But you have a couple of options:
Create your own TreeView class that inherits from the base class,
then add a bool property to prevent the events from processing.
Then you can override BeforeCollapse, etc. to check the bool
before calling base.BeforeCollapse.
Just create a bool flag, and check the flag in each of the events.
No there is no way to do that for that type of event (you are asking for TreeView).
Like for example could be managed KeyEventArgs.Handled via built-in mechanism.
You can use some instance (boolean ?) value to manage the flow,
or you can, unsubscribe from the event that you don't want more recieve, but after subscribe to it again. Sounds rough solution, but sometimes turns out reasonable one.
even if the event are raised nothing will happen if you don't bind an event handler to them. In this case you can just remove the handler using the code below:
object.Event -= new EventHandlerType(your_Method)
Otherwise you should create your own custom control
according to OnBeforeCollapse you get an TreeViewCancelEventArgs which has an Cancel property. Setting this to true should stop the flow, but will also not collapse it.
Same goes for OnBeforeSelect.
The only times you can easily "cancel" an event is if the event handler has the CancelEventHandler delegate type. Even then it doesn't really cancel it as much as set a flag for the remaining events that makes it skip performing all the events subscribed to it.
If you did have a CancelEventHandler type (which these don't) you'd simply set Cancel to true on the event object itself in the handler.
Plenty of other answers give you suggestions for what you should o. I'd just go with your idea: set a 'event cancelled' flag in your control class, and check it. When the last event in the series gets called, reset it.
Which one of these solutions looks nicer, and is more clearer?
In form's constructor:
textBox1.KeyDown += delegate(object o, KeyEventArgs e)
{
if (e.KeyCode== Keys.Enter)
{
button1.PerformClick();
}
};
Or:
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Return)
{
button1.PerformClick();
}
}
The choice of the implementation depends upon your requirements that we don't know exactly and that may change over time.
As long as your handler is not supposed to be added or removed dynamically or to contain any data that is known only at runtime I see no reason to wrap it into a delegate and add to your form. And you will need to implement your own destructor/Dispose() method to explicitly remove this handler to prevent memory leaks.
So, the second solution with static handler seems to me to be optimal here. You can then easily see what event handlers your textBox1 control actually implements directly in the properties of the control in Visual Studio and don't have to look for this handler implementation through your code if you need to modify it later.
The first one looks OK when you only have one event handler. However, what if you have 10 or 20? That would result in a pretty bloated constructor. It's definitely better to have the event handler, but even then it's best not to have a lot of business logic in an event handler.
Also, the uses of delegates in the constructor would prevent edit and continue from working.
It depends: if you could do it at design time I prefer the second.
If you use the first, remember to use textBox1.KeyDown -= before closing your form to avoid memory leaks.
According to me, the second is more clearly and look nicer, but the first help developers coding faster.
But, two solutions depend on your purpose.
It is a matter of style, but, personally, I avoid making anonymous delegates with more than one line of code. For instance, this works form me
btnSave.Click += (sender, e) => Save();
#Marco, Alexander:
How can one leak memory with those event handlers? I think it happens only if event source is static.
C# WinApps: Is there any way that I can check if something like CTRL-V is pressed but not in the KeyDown,PreviewKeyDown,KeyPress,etc ... events? those are being eaten by some other parts in my App and it is so hard to find them so I thought Ok for this contorl lets check the pressed keys in its GotFocus event! Is it possible?
Not sure what you mean by the events being "eaten". Events can call multiple handlers. So even if the event is already being subscribed to by one handler, you can subscribe to it with another handler and it should work just fine.
Another option would be to subclass the control you are using and use the subclass instead. Then you can override the On{event} methods and do anything you want with those (be sure to call the base method as well to ensure the behavior of the original class is still in place).
HTH
In VS2008, if I double click on the event handler VS creates a default event handler with a default name, e.g. combobox1_SelectedIndexChanged.
Say, for example, i now rename combobox1 to cbStatus. It still has the same event handler, so i now change that to cbStatus_SelectedIndexChanged.
Is there a way, where VS can change the initial combobox1_SelectedIndexChange to cbStatus_SelectedIndexChange rather than generate a new cbStatus event handler in addition to the old event handler? Because every time i have to cut and paste the code to the new event handler and then delete the old one.
In addition, if i have defined the initial event handler and then no longer require the handler, i cannot simply delete the handler from code, as the form designer then complains that it cant find the original event handler. Is there a way where VS can automatically remove the assignment of the event handler from the form designer?
I seem to be spending all day cutting and pasting, and deleting event handler assignments from the forms designer code.
When you rename the control, you should rename the event handler too. The proper way to do this is by refactoring the code.
To do this, just right-click the name of the event handler in the Visual Studio code editor and choose Refactor -> Rename... That will allow you to automatically change the name of it everywhere it's used.
In the case of an event handler, it's probably only used in one other place (the point in code where it's added to the event), so it's not too much trouble to change it manually. You can apply this technique to pretty much anything, though, making it extremely useful when something you're changing is referred to from several different places.
You just have to find the place in the generated code where the combobox1_SelectedIndexChange method is declare and change the name to cbStatus_SelectedIndexChange.
After you change the method name, you also have to update the line where you register the handler:
cbStatus.SelectedIndexChange += new
SelectedIndexChangeEventHandler(cbStatus_SelectedIndexChange);
Just type the new name, then recompile. By this I mean - Change
protected void combobox1_SelectedIndexChanged(object sender, EventArgs e)
{
}
to
protected void renamedcombobox_SelectedIndexChanged(object sender, EventArgs e)
{
}
and then recompile
Visual Studio will throw a compile-time error, because the method that is expected is no longer there.
Double-click on the error in the Output window to go to the assignment of the error handler, and change the error handler there to match the new function name.
Edit - added
The above step will jump you to the line of code described in Justin's answer...
End Edit
I know that's clear as mud, but try it and you'll figure it out with little or no difficulty.
If you single-click instead of double-clicking to automatically create the event handler, you can specify the handler name you want. You could make it something like "SelectedStatusChangedHandler", which is independent of the combobox's variable name. Then press 'enter' and let VS create the handler for you.