Heyo,
I have a standard WinForms MonthCalendar in my application with a handler hooked up to the DateChanged event. Whenever I change the date by day, clicking on a certain date in the little calendar, the event fires once. However, whenever I change the date by month, clicking on the < and > in the control, the event fires twice. I want the event to fire once in all situations.
Any ideas?
EDIT: I debugged and found out that the SelectedItem or Range is the same on the first and second handler call. So I need a way to differentiate between the first and second call while still allowing for proper handling when the event only fires once.
The handler code was requested, here it is, but it has nothing to do with the event firing multiple times:
List<TimestampInfo> displayTimestamps = databaseManger.QueryForTimestamps(DayPicker.SelectionRange);
if (displayTimestamps == null) return;
TimestampsListBox.Items.Clear();
TimestampsListBox.Items.AddRange(displayTimestamps.ToArray());
Somewhat of a hack, but compare the SelectionRange string value with the last DataChanged event. Just run your code if it's different:
private string _LastRange = string.Empty;
private void monthCalendar1_DateChanged(object sender, DateRangeEventArgs e) {
if (monthCalendar1.SelectionRange.ToString() != _LastRange) {
_LastRange = monthCalendar1.SelectionRange.ToString();
List<TimestampInfo> displayTimestamps = databaseManger.QueryForTimestamps(DayPicker.SelectionRange);
if (displayTimestamps == null) return;
TimestampsListBox.Items.Clear();
TimestampsListBox.Items.AddRange(displayTimestamps.ToArray());
}
}
I couldn't reproduce this until I hooked up the event handler twice.
monthCalendar1.DateChanged += new System.Windows.Forms.DateRangeEventHandler(this.monthCalendar1_DateChanged);
monthCalendar1.DateChanged += new System.Windows.Forms.DateRangeEventHandler(this.monthCalendar1_DateChanged);
Is you code munging around with the event handlers?
Try this:
private void monthCalendar1_DateChanged(object sender, DateRangeEventArgs e) {
Calendar1.SelectedDate = Calendar1.VisibleDate;
// any additional code optional
}
Related
OverView
I have researched out there an I know there is a vast amount of info subscribing multiple event handlers to a single event however, I have not been able to apply it to my scenario. Pretty much I have a bout 30 of these validation event handlers from a textBox, all doing he same process. Below is one of those handlers:
private void txt_HouseName_Validating(object sender, CancelEventArgs e)
{ // Convert User input to TitleCase After focus is lost.
if (Utillity.IsAllLetters(txt_HouseName.Text) | !string.IsNullOrEmpty(txt_HouseName.Text))
{
errorProvider.Clear();
txt_HouseName.Text = Utillity.ToTitle(txt_HouseName.Text);
isValid = true;
}
else
{
errorProvider.SetError(txt_HouseName, "InValid Input, please reType!!");
isValid = false;
//MessageBox.Show("Not Valid");
}
}
How would I minimizes my code to just one of these lines of code and only have one of these event handler?
I know I should attach them within the designer code something similar to this
this.txt_Fax.Validating += new System.ComponentModel.CancelEventHandler(this.txt_Fax_Validating);
But as they are textboxes How would I go about attaching 1 validating events handlers to all of my TextBoxes
You should be using the object sender parameter. as the sender is nothing but the object that called the Event Handler. So, have a global event handler and attach the same handler to all the text boxes. Your Event handler will look something like this.
private void txt_Validating(object sender, CancelEventArgs e)
{ // Convert User input to TitleCase After focus is lost.
//Cast the sender to a textbox so we do not need to use the textbox name directly
TextBox txtBx = (TextBox)sender;
if (Utillity.IsAllLetters(txtBx.Text) | !string.IsNullOrEmpty(txtBx.Text))
{
errorProvider.Clear();
txtBx.Text = Utillity.ToTitle(txtBx.Text);//using the cast TextBox
isValid = true;
}
else
{
errorProvider.SetError(txtBx, "InValid Input, please reType!!");
isValid = false;
//MessageBox.Show("Not Valid");
}
}
Since the object sender parameter is passed with almost every event, it makes it easy to have a common callback for similar events and just check the sender and perform specific operations.
I am making an asynchronous call to wcf service methods and generated a Completed event on Button click:
private void OnSearchProductClick(object sender, RoutedEventArgs e)
{
service.GetProductsCompleted += new EventHandler<GetProductsCompletedEventArgs>(webService_GetProductsCompleted);
ProductType productType = (ProductType)cboProductType.SelectedItem;
_productTypeID = productType.ProductTypeID;
service.GetProductsAsync(txtName.Text, txtCode.Text, _productTypeID);
}
Problem is, the webService_GetProductsCompleted event gets called multiple times. When click the Button for first time it gets called once, when I click second time gets called twice when click third time gets called thrice and so on. This is a very unusual behavior. Why is it happening and how can I resolve it?
Here is the webService_GetProductsCompleted event:
public void webService_GetProductsCompleted(object sender, CatalogueServiceReference.GetProductsCompletedEventArgs e)
{
if (e.Result.Count != 0)
{
PagedCollectionView pagingCollection = new PagedCollectionView(e.Result);
pgrProductGrids.Source = pagingCollection;
grdProductGrid.ItemsSource = pagingCollection;
pgrProductGrids.Visibility = Visibility.Visible;
}
}
The problem is this line:
service.GetProductsCompleted += new EventHandler<GetProductsCompletedEventArgs>(webService_GetProductsCompleted);
You should call it from the form Load event, not here. Because every time you call these methods (OnSearchProductClick) you add the same handler again so it gets executed multiple times.
Other option is un-register it first and then register it again.
problem is here.
private void OnSearchProductClick(object sender, RoutedEventArgs e)
{
service.GetProductsCompleted += new EventHandler<GetProductsCompletedEventArgs>(webService_GetProductsCompleted);
}
By doing this, you are subscribing event in click event, thus on every click you are making new subscription.
Instead of this, you should be subscribing service's event once (before this click event, usually in load event of form or in constructor as per your convince).
But one thing you should keep in mind, this "service" object should be the same while subscribing event and calling API.
following link may clear this idea
https://msdn.microsoft.com/en-us/library/ms366768.aspx
Well, I have the following problem:
I need to delete a row from a bindingsource without fireing the CurrentChanged event. Deletion is working without any problems. But it raises the CurrentChanged event instantly, which leads to my code matching to the CurrentChanged event is being executed. That leads to a problem.
Is there any way to achieve a similar effect like .Delete() without raising the event?
Deleting a row will always raise the event, if there are any subscribers.
If the event code is under your control, you could set a flag which you check in the BindingSource_CurrentChanged event handler:
private void DeleteRow()
{
this.justDeletedRow = true;
this.bindingSource.DeleteRow(...);
}
protected void BindingSource_CurrentChanged(object sender ...)
{
if (this.justDeletedRow)
{
this.justDeletedRow = false;
return;
}
// Process changes otherwise..
}
If the code isn't under your control - if you're binding to a component, say - then you can unbind the handler while performing the operation:
private void DeleteRow()
{
this.bindingSource.CurrentChanged -= this.component.BindingSource_CurrentChanged;
this.bindingSource.DeleteRow(...);
this.bindingSource.CurrentChanged += this.component.BindingSource_CurrentChanged;
}
I was wondering about this problem for a while, but couldn't really come up with a solution. I have 2 different event handlers calling each other recursively. As soon as event A is fired, it triggers event B which triggers event A again and so on...
Basically I want to be able to select text in a RichTextBox and show the corresponding font size in a combo box. When I choose a different font size from the ComboBox, I want it's value to be applied to the selected text.
The 2 events are:
1) The selection changed event of text inside a RichTextBox:
private void MyRTB_SelectionChanged(object sender, RoutedEventArgs e)
{
//Get the font size of selected text and select the concurrent size from the ComboBox.
}
2) The selected index changed event of a Combobox:
private void CmbFont_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
//Apply the chosen font size to the currently selected text of the RichTextBox.
}
What would be the best solution to make sure they each only "do their thing" and do not fire the other event in doing so?
Sometimes changing a property of a control in code fires an event unintentionally. Changing the data source of a ListBox or a ComboBox will fire the SelectedIndexChanged event, for example. Use a flag to handle this case
private bool _loading;
...
_loading = true;
// Fill the ComboBox or ListView here
_loading = false;
In the event handler do this
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (_loading) return;
...
}
Refactor your code so that A calls DoSomethingA() and B calls DoSomethingB(). This way, if you want A to do the functionality of B you can just call DoSomethingB() and not have any recursive calls.
Just use a bool (maybe called dontFireA) and set it in A just before calling B
notifying properties (used in order to enable binding from WPF to non-WPF properies) use this technique:
public object MyProperty
{
get
{
return myField;
}
set
{
if (value != myField)
{
myField = value;
NotifyProperyChanged("MyProperty"); // raise event
}
}
}
The if (value != myField) condition prevents infinite recursion (stackoverflowexception).
In some cases (e.g. floating point numbers and inaccurate value transfers) if (Math.Abs(value - myField) > someConstant) is used instead to break the recursion.
Could you apply a similar technique to your problem?
If both events are on the same object or the owners have references to each other, you could also store a flag on each e.g.
private void OnEvent()
{
DoSomething();
}
private void DoSomething()
{
this.IsBusy = true;
// do work
// raise event
if (!other.IsBusy)
RaiseEvent();
}
I am going to make the educated guess that you are not raising Event A or Event B yourself; let's say Event A is the TextBox1.TextChanged event and Event B is the TextBox2.TextChanged event, and they have handlers like:
public void Textbox1_TextChanged(object sender, EventArgs e)
{
...
TextBox2.Text = someString;
}
public void Textbox2_TextChanged(object sender, EventArgs e)
{
...
TextBox1.Text = someOtherString;
}
In this case, the handlers are each going to raise the other textbox's TextChanged event by virtue of changing the text, leading to infinite recursion.
The first thing you can do, if you want both to run once and once only, is to mark that they're already running (changing the text of the other textbox results in that textbox's event handler running within the same call stack:
public void Textbox1_TextChanged(object sender, EventArgs e)
{
if(handler1Running) return; //the second time through we exit immediately
handler1Running = true;
...
TextBox2.Text = "Something"; //the other event handler is invoked immediately
handler1Running = false;
}
public void Textbox2_TextChanged(object sender, EventArgs e)
{
if(handler2Running) return; //the second time through we exit immediately
handler2Running = true;
...
TextBox1.Text = "Something Else"; //the other event handler is invoked immediately
handler2Running = false;
}
Now, the deepest it will go is three levels; 1's handler invokes 2's handler which invokes 1's handler again, which sees that 1's handler is already running and quits before doing anything that would deepen the recursion. Same thing if you start by changing TextBox2.
The other thing you can do is make sure you aren't trying to set the textbox to the same value that's already there. Changing from one string reference to another, even if both references are the same string value, will fire the TextChanged event. If the recursion must continue naturally but will reach a steady state, this is actually the first thing to try:
public void Textbox1_TextChanged(object sender, EventArgs e)
{
StringBuilder builder = new StringBuilder();
... //build string
//now, even though the builder's ToString will produce a different reference,
//we're making sure we don't unnecessarily change the text.
if(builder.ToString != TextBox2.Text)
TextBox2.Text = builder.ToString();
}
public void Textbox2_TextChanged(object sender, EventArgs e)
{
StringBuilder builder = new StringBuilder();
... //build string
//now, even though the builder's ToString will produce a different reference,
//we're making sure we don't unnecessarily change the text.
if(builder.ToString != TextBox1.Text)
TextBox1.Text = builder.ToString();
}
I want to allow the user to send his message when he press enter in the textbox.
I went to search and im using the sample codes below.
Now the problem is when i press enter, the event is triggered more than once like about 4-5 times.
Someone else suggested to use keyup. I have tried keyup, keydown and keypress. All have the same problem.
How do i prevent it from firing the event more than once?
private void tbxAnswer_TextChanged(object sender, EventArgs e)
{
tbxAnswer.KeyUp += new KeyEventHandler(tbxAnswer_KeyUp);
}
private void tbxAnswer_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyValue == (char)13)
{
MessageBox.Show("Hello");
}
}
Thank you!
You are adding the KeyUp event handler multiple times (inside the TextChanged handler); therefore, when Enter is pressed, the handler executes multiple times.
What you want to do here is add the KeyUp handler just once, inside your form's constructor, just after the InitializeComponent() call:
public MyForm()
{
// other code possibly here
InitializeComponent();
// and now add the event handler:
tbxAnswer.KeyUp += new KeyEventHandler(tbxAnswer_KeyUp);
}
private void tbxAnswer_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyValue == (char)13)
{
MessageBox.Show("Hello");
}
}
This is because every time you change the text, the tbxAnswer_TextChanged is called/ fired you assign an action to the keyup event; if the text is changed 4 times then you assigned the keyup event 4 times and it increases every time you change the text.
try this out:
tbxAnswer.KeyUp += new KeyEventHandler(tbxAnswer_KeyUp);
private void tbxAnswer_TextChanged(object sender, EventArgs e)
{
}
private void tbxAnswer_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyValue == (char)13)
{
MessageBox.Show("Hello");
}
}
Change your code to this
tbxAnswer.KeyUp -= tbxAnswer_KeyUp;
tbxAnswer.KeyUp += new KeyEventHandler(tbxAnswer_KeyUp);
In your code snippet, whenever the text of the TextBox changes, another eventhandler is added to the KeyUp handler. You should only add event handlers once (for instance, just after creating the textbox).
Sara and Jon have already provided the correct answer to your specific question. But if you want to go further and get a better understanding of how and when to use any particular key handling event take a look at my article Exploring Secrets of .NET Keystroke Handling. I explain and diagram when and where each event is useful, plus provide a KeystrokeSandbox application that lets you actually watch what happens!