Stop events in WPF - c#

Is it possible to stop/suspend raised events in WPF? I want to stop events like SizeChanged, LocationChanged, MouseDown, when my window touches a screen side.
For now on I cannot modify window dimensions, because somehow other events overwrites the values.
EDIT I've discovered, that my problem is caused by raised events which overwrites my window object (i guess so), because when I've printed window dimensions in all the events, it occurred that after change other event causes setting original dimensions.

To unsubscribed from an event just type this in the place where you want to stop.
eg: SizeChanged;
this.SizeChanged -= MethodName;

AFAIK you cannot suspend firing of events. You can either unsubscribe using EventHandlerssimilar to subscribing them:
object.someEventHandler -= someMethodOrDelegate
or you can suppress the bubbling up/tunneling down of event based on special condition:
private void SomeEventHappened(object sender, RoutedEventArgs e)
{
if(someCondition)
e.Handled = true;
else
DoSomeWork();
}
As per your edit on question and your comments, as far as I understood you have events that change window dimensions, and these prevent you from resizing window manually. Moreover, your eventhandlers are not WPF originated (they use EventArgs instead of RoutedEventArgs). If I understood correctly, a solution may be having a class-scoped (or internal, based on your needs) boolean variable that holds whether to allow/overwrite dimensions or not:
bool allowManualResize = false;
And then when you are doing size modifications manually, you set this variable to true:
private void SomeManualSizingEventHandler(object sender, EventArgs e)
{
allowManualResize = true;
....
After these, you can check for this value in your events that override your new values:
private void SomeUpperLevelResizeHandler(object sender, EventArgs e)
{
// Check if resizing is allowed,
if(!allowManualResize)
{
// do your default things here
....
Of course you need to find a suitable location to set allowManualResize to false so that future firings are not suppressed.

Related

Calling a KeyDown Event on Form Load

I would want to launch a KeyDown Event on Form_Load however its taking me somewhere else in the Form_Load event.
Form_Load:
int static_int = 0;
private void Form1_Load(object sender, EventArgs e)
{
if(condition == true)
{
txtInput.Text = "something";
txtInput.Focus();
SendKeys.Send("{Enter}");
int somegeneratednubmer = 20;
static_int = static_int + somegeneratednumber;
//somemore code here
}
}
KeyDown:
private void txtInput_KeyDown(object sender, KeyEventArgs e)
{
if(e.KeyCode == Keys.Enter)
{
static_int = 10;
//somemore codes here too
}
I would like to get the SUM of static_int and somegeneratednumber which is 30. However, after Debugging, I'm getting its initialized value of 0. From what I understood, after SendKeys.Send("{Enter}") the KeyDown event should proceed.
Why is it not??
How would I get the correct result? I really should do the KeyDown event on Form_Load, a conditional event...
or What am I doing wrong here?
Note: originally static_int is initialized on a Class
No, the KeyDown even will proceed at the earliest possible moment, which is when the appropriate message is executed from the form's message queue. That cannot happen before the Load event finishes, because that also on the message queue. Even if that weren't the case, SendKeys doesn't wait for the action to be processed. It just sends the message and returns immediately.
Another problem is that SendKeys sends the virtual keys to the currently active window. That can never be your window, since your window isn't even shown yet! When something behaves weird, a good first step is to read the documentation.
So, why is the value of static_int zero, instead of 20 or 30? Well, the likeliest case is an unhandled exception, and I'm pretty sure that's exactly what happens when you do tbxInput.Focus. The control doesn't quite exist yet, and it can't be made the input focus. If you have trouble understanding all this, you might want to find some book on the basics of how Windows windows work - there's nothing .NET can do about it, and it's places like this where the (very pretty) .NET abstraction leaks a lot. If you're planning to do any Windows UI development, you really need to know at least the basics.
However, that's completely unnecessary anyway. You don't have to execute a KeyDown event. Just make a method that's called from both the Load event handler and the KeyDown event handler.
try adding this event instead
Form1 isn't loaded yet so no events yet.
private void Form1_Shown(Object sender, EventArgs e)
{
SendKeys.Send("{Enter}");
}
But truly this design is wrong

FlatStyle.System raise strange MouseHover event

With the following code, when i move the mouse into the button and click it, the final value of result is 2 instead of 1.
static int result = 0;
private void button2_MouseHover(object sender, EventArgs e)
{
result++;
}
private void button2_MouseDown(object sender, MouseEventArgs e)
{
button2.FlatStyle = FlatStyle.System;
}
I had tried different setting:
Using MouseEnter instead of MouseHover give result = 1
Only changing of FlatStyle to System will trigger MouseHover one more time after button is clicked.
If the FlatStyle of button is originally FlatStyle.System, give result = 1;
If the FlatStyle is changed to others Style(popup, flat), give result = 1;
So i guess the problem lies with the FlatStyle set to FlatStyle.System, anyone can explains this to me?
This is a fairly common quirk in Winforms. You can visualize what's going with this code:
private void button1_MouseHover(object sender, EventArgs e) {
Console.WriteLine("{0:X}, {1}", button1.Handle, DateTime.Now.TimeOfDay);
result++;
}
Look in the Output window for the displayed diagnostic. On mine:
12780286, 03:04:10.7619696
12780286, 03:04:16.2935137
12780286, 03:04:20.1062178
12780286, 03:04:23.9970596
Click
12845822, 03:04:28.9191911
12845822, 03:04:32.3099880
Note how the Handle property value changed after the click. In other words, the physical Windows window changed. This happened because you changed the FlatStyle property. Winforms implements this by destroying the button control window and recreating it. If you look really close then you can actually see this, the button briefly flickers.
There are a few properties that are implemented like this, they are "heavy" properties that requires the window to be recreated since the style flags changed. Style flags that are passed in the native CreateWindowEx() call. A change in those style flags requires another call to CreateWindowEx().
This tends to have side-effects. Destroying the old window causes its state to be lost. Winforms tries to restore the state of the new window as best it can, but there are a few it cannot get to. The "window was hovered" state is one of them. Clearly the new window has that internal state flag set to false. Which is why you get the MouseHover event again. You'll need to work around this quirk.

SizeChanged event being fired recursively

I have a SizeChanged event in one of my windows. One of the user controls Width's is behaving interestingly, so I decided to staticly set the width of my window in a SizeChanged event. Problem is, when I set the size of the window in the size changed event, it fires another size changed event! I want the user to be able to resize the window, and then only have the event fire once. I have tried :
e.Handled = true;
As well as adding an event handler in the window constructor, and removing it in the size changed event. (This makes it only be able to fire once and won't ever fire again in the window's lifetime). Any ideas?
you should use a private bool and change its value when the size changed
bool _sizeChanged=false;
void handleResize(Object sender, EventArgs e)
{
if (_sizeChanged==false)
{
// do stuff
}
_sizeChanged=true;
}
But is is not enough, because you should change its value again somewhere else. if you do not change its value (for example to false somewhere else) it will never pass the 'if' condition again. So the question is, where you should change its value.
I think you can change the value at MouseButtonUp event, since resizing is done with the mouse.
You can use a boolean to determine whether or not to handle your event.
private bool m_handleResizeEvent;
private void HandleResize(object sender, EventArgs e)
{
if (m_handleResizeEvent)
{
m_handleResizeEvent = false;
// perform your resize here
m_handleResizeEvent = true;
}
}
Turns out it was the SizeToContent="Width" property in my Window's XAML that was causing the SizeChanged to be called multiple times. Removing this property fixed my issue and allowed me to resize the window without the event being fired multiple times. Thanks everyone else for your answers and input!

How to handle the user changing his mind without boolean flags?

I have a NumericUpDown in my application but it is dangerous. When the value is changed the entire document is erased. Because of this, I'd like to give the user a warning (even if he accidentally hits OK he can undo it.)
The problem is that it seems that the only event I could handle would be the ValueChanged event and I'd end up with code like this.
private bool ignoreValueChanged = false;
private void numFoobar_ValueChanged(object sender, EventArgs e)
{
if (ignoreValueChanged)
{
ignoreValueChanged = false;
return;
}
if (MessageBox.Show("This will erase the entire document. Are you sure?", "Confirmation", MessageBoxButtons.OKCancel) == DialogResult.Cancel)
{
ignoreValueChanged = true;
numFoobar.Value = oldValue; // The ValueChanged event gets called again =/
return;
}
// More code
}
There has got to be a better way. I was hoping Validating would help but it is only called when closing the form it seems.
Oh well you could remove the event subscribed to the numericUpdown control before resetting its value, after resetting it then again subscribe it back. This way, the event is not called when you reset the value.
But i am also thinking about how to check if the event is already subscribed or not. But above said method shall give you half the solution.
Here i tried this a bit and it seems to work but i cant seem to figure out how to check if already that same event is subscribed or not.
void NumericUpDown1ValueChanged(object sender, EventArgs e)
{
if(numericUpDown1.Value > 10)
{numericUpDown1.ValueChanged -= new System.EventHandler(this.NumericUpDown1ValueChanged);
numericUpDown1.Text = "5";
}
else numericUpDown1.ValueChanged += NumericUpDown1ValueChanged;//Here i need to first check if already it is subscribed or not before such that i dont want to subscribe double time
}
Did some Googling, and here's something that might work:
private void numFoobar_ValueChanged(object sender, EventArgs e)
{
this.ValidateChildren();
}
private void numFoobar_Validating(object sender, CancelEventArgs e)
{
if (MessageBox.Show("This will erase the entire document. Are you sure?", "Confirmation", MessageBoxButtons.OKCancel) == DialogResult.Cancel)
{
e.Cancel = true;
}
}
Note that you'll need to reset the value as canceling the validation doesn't change the value. But this is the only way I was able to get the Validating event to fire.
ContainerControl.ValidateChildren Method
There are couple of issues to work out with this, however:
When exiting the program, it will fire the Validating event again; probably need to handle it in one of the closing events for the form or application.
I played with resetting the value in the ValueChanged event, but that trigged the Validating event again.
I'll keep playing with it for a bit and see if I can come up with a more solid solution for you.
This is really a usability issue. I guess what you are trying to do is to ignore the valueChanged event when the value has changed to the current persistent value. One option is to compare with the current value the document is based on.
Been googling a bit. First, I came up with this:
typeof(NumericUpDown).GetField("currentValue", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(numericUpDown1, 5m);
Which works but it is reflection and it seems a little over the top so I decided against it. Then I found this:
C# winforms numericupdown control
And based my solution on the second answer, which isn't so bad to be honest.

Triggering an event after a Winform layout is complete

I am working on a C# WinForm application.
I want to trigger some processing once the form has been "shown" and the layout of the form is complete.
I am using the "_Shown" event, but this seems to trigger before the layout of the form has completed. Is there event I can use that fires once the layout is complete?
Put Application.DoEvents() at the start of the form's Shown event handler. This will force all the controls to be rendered.
I don't see an event after Shown you can use for this purpose. Could you not use a timer to delay your processing in the Shown event?
An old trick in VB6 used to be to use the Paint event:
bool firstShown = false;
void form_Paint(Object sender, EventArgs e) {
if ( !firstShown ) {
YourMethodThatNeedsToRunOnShown();
firstShown = true;
}
//the rest of your paint method (if any)
}
It is a little hacky, but it does work
This works for me and is much less "hacky" than other suggestions:
protected override void OnLayout(LayoutEventArgs levent)
{
base.OnLayout(levent);
if(someControl == null)
return; // be careful of OnLayout being called multiple times
// otherwise, do some stuff here, set control sizes, etc.
}
AS far as I can remember the event order is something like
Form.Load
Form.Layout
Form.VisibleChanged
Form.GotFocus
Form.Activated
Form.Shown
So if something is still happening after Form.Show it's because of the way you coded it.
Are you maybe creating the form dynamically?
The best solution is the Shown() event: http://msdn.microsoft.com/en-us/library/system.windows.forms.form.shown.aspx
"The Shown event is only raised the first time a form is displayed; subsequently minimizing, maximizing, restoring, hiding, showing, or invalidating and repainting will not raise this event."
Try using Form.GotFocus (inherited from control)..
something like this.
private void Form1_Load(object sender, EventArgs e)
{
this.GotFocus += new EventHandler(Form1_gotFocus);
this.Focus();
}
private void Form1_gotFocus(object sender, EventArgs e)
{
// You will need to Switch focus from form at the end of this function,
//to make sure it doesnt keep Firing.
}
According To msdn , the following happens:
When you change the focus by using the keyboard (TAB, SHIFT+TAB, and so on), by calling the Select or SelectNextControl methods, or by setting the ContainerControl..::.ActiveControl property to the current form, focus events occur in the following order:
Enter
GotFocus
Leave
Validating
Validated
LostFocus

Categories

Resources