I have made my own Button User control in a WPF application.
In this, I'm trying to raise a event attached with multiple event handlers on another event.
I have multiple event handlers attached with "MouseUp" Event for View and business logic (MVVM). I just want to fire all the handlers attached with "MouseUp" event On "KeyUp" with "Enter" and "SpaceBar"
Here is the sample code which I used to raise "MouseUp" event on "KeyUp" if the key is enter or space
void Button_KeyUp(object sender, KeyEventArgs e)
{
if (e.Key == Key.Space || e.Key == Key.Enter)
{
RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left)
{
RoutedEvent = Mouse.MouseUpEvent,
Source = this,
});
}
}
Not sure. I may be wrong. But it worked for me. However, not in all case.
In some of the cases, the event not raising as expected.
In my further investigation, Im seeing the key up event get triggered. But the none of the event handlers in "MouseUp" event raised in some objects.
Is there any elegant way to achieve my need.
This breaks the expected pattern for anyone reading the code - why would the mouseup event need to be fired when the key is released? If it's just to avoid code duplication, you should have a separate method which both the mouseup and the keyup call.
As per the comments, if you have multiple event handlers attached, you will need to attach all of them to both events. Alternatively, you could create a meta-event-handler that calls all the others as methods, then just attach that one to each event.
Just create function and work with events separately, adding reference to this function as events handler.
Related
I have the following problem with System.Windows.Forms (C#):
I have a CheckBox in my program and I defined an event handler for CheckedChanged. The problem is that when the user clicks the CheckBox, it may happen that it takes several seconds until the CheckBox is visibly marked as checked.
I set a breakpoint inside the CheckedChanged event and noticed that indeed, it sometimes takes several seconds until the CheckedChanged event fires. How can it be that the CheckedChanged event lags behind that much?
Unfortunately I have not been able to find information in the literature regarding the matter when exactly the CheckedChanged event is triggered. Might it be that another event is handled first before the CheckedChanged event is triggered, so I could catch this event instead and make the check-arrow appear in time?
Thank you for your help and suggestions.
The CheckedChanged event occurs when the Checked property of the CheckBox changes.
The UI will not update the checkmark inside the checkbox, until after any eventhandler for this event has been handled. If you are doing a lot of processing in the handler for the CheckedChanged event, then it will take some time before the checkmark is added/removed from the checkbox.
If you need the UI to update quickly, then consider doing the processing in a separate thread. This can be done pretty easily, using Task.
Here's a quick example:
private void MyCheckBox_CheckedChanged(object sender, EventArgs e)
{
//Don't do this:
//ThreeSecondMethod();
//Instead, do this:
Task.Run(() => ThreeSecondMethod());
}
private void ThreeSecondMethod()
{
DateTime deadline = DateTime.Now.AddSeconds(3);
while(DateTime.Now < deadline)
{
/* Do nothing */
}
MessageBox.Show("Done!");
}
had the issue that my KeyUp and the KeyDown Event both fired twice when i invoked them. Finally found a fix for this:
this.glControl1.KeyUp -= this.glControl1_KeyUp;
this.glControl1.KeyUp += new KeyEventHandler(this.glControl1_KeyUp);
It works, but i really cant understand why. Could anyone explain me please.
Thank you
You probably have some repetitive event which you use as a trigger to hook up your event handler, a classic example is a button click e.g.
public void ButtonClick(object sender, EventArgs e)
{
this.SomeControl.KeyUp += this.SomeHandler;
}
The problem here is everytime the button is clicked the same event handler is assigned to the same event, there is nothing to prevent this from happening as it can be perfectly acceptable under certain circumstances.
To avoid this, you need to unhook the event handler before you reassign it, this is why executing the following line of code
this.SomeControl.KeyUp -= this.SomeHandler;
Before you assign the event handler prevents duplicate calls.
So I've had an argument with a friend, basically he is saying that this an event handler and I am stating that this is a method. Can you please tell me who's right, and explain what makes this an event handler, if so?
Control ctrlClick;
private void NextColour(object sender)
{
ctrlClick = sender as Control;
// More Code Here
}
Did you subscribe this method to an event like someEvent += NextColour;? Then it's an event handler. Otherwise just a method.
An event handler is a method subscribed to an event, and as it's name implies it gets called back in order to handle the occurrence of the event,once it gets notified by the event publishing mechanism.
If the method has not been subscribed to handle an event, then there is no event for it handle, meaning it's just a method ( maybe a very important one ... :) but still just a method).
I am programming a calculator in C#, and I am trying to add keyboard input to it. The problem is if I click a button on the GUI then the Enter/Return key gets focused on that. When the return key is pressed it then clicks that key again, instead of being handled by my KeyDown event handler. How can I fix this?
private void Window_KeyDown(object sender, KeyEventArgs e)
{
switch (e.Key)
{
case Key.NumPad1:
case Key.D1:
addInput('1');
break;
case Key.Return:
MessageBox.Show("Enter!");
break;
}
}
You need to handle PreviewKeyDown event of your form. Then check if you want to handle the event, and if you do, set Handled property of the event to true after you do.
That would probably look something like this:
public MainWindow()
{
InitializeComponent();
PreviewKeyDown += new KeyEventHandler(MainWindow_PreviewKeyDown);
}
void MainWindow_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Space)
{
Log("Intercepted space in preview");
e.Handled = true;
}
}
Why do you need to set Handled to true? Events in WPF are triggered on several UI elements, in manner which depends on it's "routing strategy". When your event handler sets Handled to true, visibility of that event will be limited to other UI elements. Shortly, it won't be triggered in other UI elements. To learn more about details of solution above, read rest of the answer below.
There are some things that you need to understand if you want to properly use events in WPF. Events are attached to UI elements (text boxes, buttons, etc), and event handlers can be connected to those UI elements. Also, UI elements are organized in a tree structure. Each element has it's parent element, up to root UI element. As already mentioned, events are triggered on multiple elements depending on their "routing strategy". Multiple elements here means element at which an event is targeted and it's parents, up until root element. Event routing strategy can be following:
Bubbling: Event is first fired for event target element. Then, it is fired for it's parent, then parent of it's parent, and so on up until root element (often this is Window)
Tunneling: Event is first fired for root UI element, and then down UI elements tree, along the route to target element.
Direct: Event is only fired for target element.
How is this related to Handled property? When event is using bubbling or tunneling routing strategy, Handled property is used to stop propagation of event down or up UI elements tree.
Now, why didn't KeyDown event stop propagating when you marked it as Handled? Because KeyDown event uses bubbling strategy. This means that a text box would already handle KeyDown event, before it get's to Window handler where you set Handled to true.
For that reason you should use PreviewKeyDown which uses tunneling strategy. Your window handler checks the event, marks it as Handled if needed. If it's marked as Handled it will not be triggered down UI tree to event target.
You can view this as a convention in .NET framework. PreviewX are events which use tunneling strategy, and are counterpart of X events which use bubbling strategy.
To learn more about Routed Events visit this MSDN page. You'll find MSDN is a good source of information about WPF.
Try this:
private void Window_KeyDown(object sender, KeyEventArgs e)
{
switch (e.Key)
{
case Key.NumPad1:
case Key.D1:
addInput('1');
MyTextBox.Focus(); // <-- NEW LINE OF CODE
break;
case Key.Return:
MessageBox.Show("Enter!");
MyTextBox.Focus(); // <-- NEW LINE OF CODE
break;
}
}
set Focusable to false:
<Button Focusable="False" Click="Button_Click" />
In C# events were always very protected: Only the owner of the event could trigger them. However, this seems to be completely different in WPF - Anyone can throw any event at any time. To test that, I've written the code in the bottom.
When I used RaiseEvent to raise Button.Click, the event above caught it. Is that the planned behavior of WPF events? Just letting anyone throw any events they wish? Also, if so, then what is the meaning of the OwnerType when you register the event? I thought it is some kind of protection, yet if it is, it is a poor one since anyone can access the public event and use AddOwner function to add more owners.
Thanks!
XAML
<StackPanel Button.Click="ButtonBase_OnClick">
<Button Name="RealButton">Real button</Button>
<WpfWindow:VitalyControl MouseDown="UIElement_OnMouseDown">
I am almost a button
</WpfWindow:VitalyControl>
</StackPanel>
Code behind
The custom control:
class VitalyControl : Label
{
public VitalyControl()
{
this.MouseDown += new MouseButtonEventHandler(VitalyControl_MouseDown);
}
void VitalyControl_MouseDown(object sender, MouseButtonEventArgs e)
{
RaiseEvent(new RoutedEventArgs(Button.ClickEvent, this));
}
}
And the handler:
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
MessageBox.Show("Button was pressed");
}
This is by design, and is actually one of the reasons for RoutedEvents. They are called routed events because they are routed across the element tree. The behavior you are experiencing is called 'singular handler attachment point' on msdn. You specify that StackPanel should listen to all Button.Click events.
In your custom control, you raise a button click event. This 'bubbles' up to the stackpanel, which handles it.
UPDATE:
For this routing to work, I assume every UIElement needs to be able to raise any routed event. Routed Events are only used by UI elements, and are an answer to complexities with WinForms implementations. They aren't a replacement for CLR events.
The owner type is used internally when resolving an event by name.