So I've been following the Visual Studio tutorials that microsoft has available (more specifically the math quiz one found at https://msdn.microsoft.com/en-us/library/vstudio/dd492172.asp)
but I deviated a bit from the tutorial because I wanted to see if I could create an event and call it using the EventHandler delegate though it might not be the best solution.
public event EventHAndler quizStarted;
here is the code for creating the event.
now in the method
public Form1()
{
this.quizStarted += new System.EventHandler(this.showThatTheQuizStarted);
InitializeComponent();
}
I have initialized my event with an instance of the EventHanlder that points to my showThatTheQuizStarted method.
public void showThatTheQuizStarted(object sender, EventArgs e)
{
MessageBox.Show("Quiz Has Started");
}
and finally when the start button is pressed I call the quizStarted event as shown below.
private void startButton_Click(object sender, EventArgs e)
{
startButton.Enabled = false;
quizStarted(this, new EventArgs());
this.StartTheQuiz();
}
in this order the message box goes away after hitting okay once, also in StartTheQuiz() nothing calles a message box directly or indirectly.
but if I place the this.quizStarted += new System.EventHandler(this.showThatTheQuizStarted); line into the startButton_Click method, the message box appears twice one right after the other.
Though I found a solution I would like to know why this happens if I place this line of code out of the constructor.
If...
this.quizStarted += new System.EventHandler(this.showThatTheQuizStarted);
... gets called multiple times, as would happen if you move it inside a button Click event handler method, then you are in fact adding and registering a new event handler every time.
In other words, when quizStarted is invoked, it may call multiple event handlers, depending on how many you choose to register. If you register the same event handler multiple times, then it will get called as many times.
That's why you want to leave the registration in a place where you are guaranteed to register the event handler once and only once.
Related
I am following this walkthrough on MSDN: Creating a Custom Tab by Using the Ribbon Designer
Looking at steps 3 and 4:
In step 3 it adds an event handler to the ribbon_Load function, basically adding a click event to a button in the ribbon:
private void MyRibbon_Load(object sender, RibbonUIEventArgs e)
{
this.button1.Click += new RibbonControlEventHandler(this.button1_Click);
}
Then, in step 4 they add another event handler in the way that I am more used to, like so:
private void button1_Click(object sender, RibbonControlEventArgs e)
{
MergeReportInterface ui = new MergeReportInterface();
ui.ShowDialog();
}
I am not really understanding the purpose of this, because all it does is cause the event to fire twice. If I comment out the event handler that was added to the load function the event occurs once.
Could someone please explain to me what the point of this is? if there is any, or if there is some error on the MSDN site. What should be the proper way to handle a ribbon click event?
private void button1_Click(object sender, RibbonControlEventArgs e)
{
MergeReportInterface ui = new MergeReportInterface();
ui.ShowDialog();
}
This is not adding an event handler. This is the method that your event will call.
this.button1.Click += new RibbonControlEventHandler(this.button1_Click);
This is saying 'When button1 fires its Click event, call this.button1_Click'.
Your code only sets up one event handler, it should only fire once.
However, it's likely you created the button1_Click method by double clicking a button on your form designer. This, behind the scenes, adds an additional event handler. This is why you're getting the event fired twice.
So you have two options:
Go back into the IDE and remove the click handler via your form designer. Go to your code and manually write the method button1_Click.
OR
Remove this line: this.button1.Click += new RibbonControlEventHandler(this.button1_Click);, as VisualStudio is doing that for you automatically.
I have several buttons, and I want them to do something when the cursor has been positioned over them for an already specified time. In this case they should just write their content in a textbox.
This is the Timer:
private static System.Timers.Timer myTimer =
new System.Timers.Timer(1500);
This is the method the buttons execute with the MouseEnter event:
private void keysHover(object sender, EventArgs e)
{
myTimer.Elapsed += delegate { keysHoverOK(sender); };
myTimer.Enabled = true;
}
And this is what gets executed if the Timer finishes:
private void keysHoverOK(object sender)
{
this.Dispatcher.Invoke((Action)(() =>
{
txtTest.Text += (sender as System.Windows.Controls.Button).Content.ToString();
}));
myTimer.Enabled = false;
}
I don't quite understand why this is happening, but everytime one of the buttons completes the Timer the keysHoverOK method will write as many characters as there have been hovered. For example, if I hover over the button A, it will write A, if I then hover over the button B, it will write AB, thus getting AAB written on the textbox and so on and so forth, the sentence executes as many times as the rest of the buttons have executed the keysHover method, even if they didn't complete the Timer themselves, it's like their content got saved somewhere. Now of course all I want the buttons to do is to write their content and their content only. So do you have an idea of what I'm doing wrong?
Do you mean the MouseEnter event? I'm not aware of any MouseOver event in WPF.
Without a good, minimal, complete code example, it's impossible to know for sure what the problem is. However, based on the small amount of code you've shared and your problem description, it appears that your main issue is that you're sharing a single Timer object with multiple controls. This is exacerbated by the fact that when one control subscribes to the Timer.Elapsed event, it never unsubscribes. So if another control enables the timer (subscribing to the event as well), both controls are notified when the timer interval elapses.
Even a single control is problematic, as it subscribes itself to the event each time the MouseEnter event is raised.
The fix is to disable the timer and unsubscribe from the event when the mouse leaves the bounds of the control, or when the timer interval has elapsed. That might look something like this:
private EventHandler _timerElapsedHandler;
// Subscribed to the MouseEnter event
private void keysHover(object sender, EventArgs e)
{
_timerElapsedHandler = delegate { keysHoverOK(sender); };
myTimer.Elapsed += _timerElapsedHandler;
myTimer.Enabled = true;
}
// Subscribed to the MouseLeave event
private void keysLeave(object sender, EventArgs e)
{
DisableTimer();
}
private void keysHoverOK(object sender)
{
this.Dispatcher.Invoke((Action)(() =>
{
txtTest.Text += (sender as System.Windows.Controls.Button).Content.ToString();
}));
DisableTimer();
}
private void DisableTimer()
{
myTimer.Elapsed -= _timerElapsedHandler;
myTimer.Enabled = false;
_timerElapsedHandler = null;
}
Other comments:
You should cast instead of using as. Only use as when a reference can legitimately be of a different type than you are checking for. Use a cast when it is always supposed to be the type you are checking for. That way, if you have a bug, you will get a meaningful exception, instead of just some NullReferenceException
The above example fixes the problem with the least disruption to your code. But really, I would make other changes too. For example, rather than storing the delegate in a field, I would just get the Content.ToString() value and store that. Then instead of using an anonymous method for the delegate instance, I would use a named method that simply uses the stored string value to append to the Text property. You can subscribe and unsubscribe the named method by name; the delegate type does the right thing even though it's using a different delegate instance for the subscribe and the unsubscribe.
Another change you might consider making is to use a different Timer instance for each control. Then you don't have to subscribe or unsubscribe as the mouse events occur; just subscribe during initialization.
Finally, especially as this is WPF code, you really should consider storing the appended text in an observable property (e.g. DependencyProperty, or implement INotifyPropertyChanged), and bind it to the txtTest.Text property rather than manipulating that property directly.
I'm assuming when you say:
This is the method the buttons execute with the MouseOver event:
You might mean the MouseEnter event?
From what I see:
You have one central timer
It will start the elapsed count down on the first button you enter
You have not stopped the timer if you leave that button before it elapses
You seem only to add delegates to the event without removing any
The code segment myTimer.Elapsed += delegate { keysHoverOK(sender); }; adds another delegate to the list of already added delegates. It does not replace the list with just one delegate.
If you leave the button before the timer elapses you need to remove the delegate from the timer elapsed event using the minus-equal operator (myTimer.Elapsed -= ....), and then stop the timer. Here you have a problem that you've created an anonymous method so you'd need:-
Research into removing anonymous methods
or
Research into removing all event handlers
or possibly the simplest menthod
Stop and destroy any running timer and create a new timer instance each time you enter the button.
I need help on firing an event within C#
Basically I have a onclick event that fires when you click on a checkbox
void OnClick(object sender, RoutedEventArgs e)
{
...
}
I need help on firing an event within C#
Basically I have a onclick event that fires when you click on a checkbox
void OnClick(object sender, RoutedEventArgs e)
{
...
}
However, I need to fire this event once another event has been fired, so within this new event, is it possible I can fire the above one?
private void DataGridCell_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
switch(dataGrid.Name)
{
case "Customer"
//fire OnCLick Event
break;
}
}
I have tried something like
??? += new MouseEventHandler(OnClick);
But I am not sure if this will actually work.
Yes you can, but only if the event is in your own class. You can't even raise a base class' event. You have a put a method in the base class to raise the event, and then call that.
The code you put there is adding another event handler, not raising an event; you don't need to do that.
If it's a button, use btnDoSomething.PerformClickEvent (winforms)
If the handler is in your code, you can call it without raising the event (commenters assume that this is what you want to do but in reaslity there are many cases where you'd need more than this) btnDoSomething_Click(null, null) - null usually works because handler code rarely cares about the sender or arguments and if you don't reference them, you don't need them.
If you can use #4, you can also refactor as mentioned. Usually not needed. But usually so easy to do you it's worth doing for clarity anyway.
For objects that map from Windows widgets of anysort, check out the SendMessage and PostMessage API calls. Wayyyy beyond the scope of this answer, though. Doesn't apply to non-windows-backed objects (but your sample implies windows).
I have a refresh button on my user control that works just fine every time I click on it. This is the code to its click event:
private void btnRefresh_Click(object sender, EventArgs e)
{
if (!RefreshFolder())
{
Notify(new string[] { "Refresh failed." });
}
else
{
Notify(new string[] { "Refreshed." });
}
}
Notify function happens to be a delegate call from my main form. This function works well when called normally. What I want to do is to raise the above event when my user control is loaded. But when I call btnRefresh.PerformClick() on the load event the application does not start and quits automatically after a short while. But when instead of the Notify function I put a MessageBox.Show("blah") the function works properly.
This is the delegate I use:
public delegate void NotifyMe(string[] messages);
And on my main form I have the following line in its constructor so that my user control can use the Notify function of the main control:
userctrlSelectManualCampaignFile.Notify += new NotifyMe(Notify);
The function works perfectly well as I said unless when I try to raise the click event. Any ideas?
Update:
Main form constructor:
public MainForm()
{
InitializeComponent();
logger = new Logger();
connectionHelper = new ConnectionHelper();
datetimeHelper = new DateTimeHelper();
userctrlSettingsGeneral.Notify += new NotifyMe(Notify);
userctrlSelectManualCampaignFile.Notify += new NotifyMe(Notify);
}
My user control constructor:
public ManualCampaignFiles()
{
InitializeComponent();
}
You're probably causing a "silent" exception to be thrown, causing your application to quit.
Such exceptions can be "swallowed" by the framework, for example within event handlers.
Try setting your debug environment to break on thrown exceptions. For this, go to the Debug > Exceptions... menu, then in the dialog that shows up, make sure to check the "Thrown" checkbox corresponding to Common Language Runtime Exceptions.
This way, when you lauch your program, it will break at the moment an exception is thrown, allowing you to figure out what is going on.
Cheers
I found the answer in another forum:
Before event raising you should check if event is not null. This is
common pattern for event raising.
Answer provided by Vitaliy Liptchinsky.
But Hans Passant's answer was also very close to truth.
Have a simple application with a start/stop button that I want to do different things depending on it's current state. If button is in Start state, execute code then change to stop state and change OnClick event to StopButton_Click and vice versa.
Can't seem to change the on-click property of the button, so using code below which works, but keeps adding instances of the event. First click executes once, second click executes twice, third executes four times, ad infinitum.
StartButton.Click += new System.EventHandler(StartButton_Click);
alternates with
StartButton.Click += new System.EventHandler(StopButton_Click);
Is there a way to REPLACE the OnClick handler instead of adding to it?
Try removing the event handler before adding a new one:
StartButton.Click -= StartButton_Click;
One option is to remove the previous event handler before adding another, but a simpler option is to just use a single event handler. The event handler can look at some internal state field to determine what to do; this will likely be easier than constantly adding/removing event handlers.
It may look something like this:
private void buttonClick(object sender, EventArgs args)
{
if(buttonState == MyStateEnum.Start)
PerformStartAction();
else if(buttonState == MyStateEnum.Stop)
PerformStopAction();
}
Then instead of adding/removing event handlers you just need to assign a different value to buttonState.
+= works with events as it does anything else. It adds to what is already there.
Try removing the existing event handler with -= and then adding the new one.