Two Controls Reference One-Another Correctly - c#

I have a ComboBox and a DateTimePicker control in a .net forms application. The desired functionality for the relationship of the two controls is that a modification to one will change the value in the other. Logic to modify the other control is in each controls change event; ComboBox "SelectedIndexChanged" and DateTimePicker "Changed" and it looks something like the following:
othercontrol.value = value;
Is there a clear way I can isolate change events from the respective controls to determine whether they were sent by the UI vs. the other control's change event to head off the loop the current setup will cause?
As I write this I realize I could probably change the other controls value by invoking the change event and passing some variation in the arguments from the corresponding change event instead of simply setting the other control's value.

You can remove the control's eventhandler before settings it's value and add it back immediately after setting the value.
othercontrol.SelectedChanged -= othercontrol_SelectedChanged;
othercontrol.value = value;
othercontrol.SelectedChanged += othercontrol_SelectedChanged;

Try this then.
Ok, it's a bit hacky but this would work:
private bool eventBubbledDate = false;
private bool eventBubbleCombi = false;
protected override MyCombi_OnChange(object sender, eventargs e)
{
if (eventBubbledDate)
{
eventBubbledDate = false;
return;
}
eventBubbleCombi = true;
myDateTime.Value = myCombi.SelectedValue;
}
protected override MyDateTime_OnChange(object sender, eventargs e)
{
if (eventBubbleCombi )
{
eventBubbleCombi = false;
return;
}
// process DateStuff here
// update other control
eventBubbledDate = true;
}
Alternatively, you could use an Enumeration to track state instead of using boolean 'flags' but I think bools are easier to demonstrate.

Related

Xamarin Forms - Check a switch has been toggled manually

I am writing a Xamarin forms application which checks whether or not a user is in a specific geo-location. When a user walks inside an area, a XAML switch is toggled from the off to on position.
farmSwitch.toggled = true;
This calls this function
farmSwitch.Toggled += (object sender, ToggledEventArgs e) => {
manualOnFarm = true;
Console.WriteLine("Switch.Toggled event sent");
changeOnFarmStatus(e);
};
I also need functionality where a user manually clicks the switch, which need to be differentiated from when the code automatically toggles farmSwitch
The reason is that I have a boolean that should only be true when the user manually clicks farmSwitch, and should be false when the switch is toggled automatically
What are my options? Ideally there would be a farSwtich.clicked() function I could call for when a user manually clicks farmSwitch, but no such luck
I don't see how you can't just differentiate between this by using some kind of marker in the code you've written that programatically toggles the switch?
So you call this programatically but you also set a boolean marker to say this is a programatic change:
private bool HasBeenProgrammaticallyToggled = false;
public void ThisIsAProgrammaticToggle()
{
HasBeenProgrammaticallyToggled = true;
farmSwitch.toggled = true;
}
and in your little on toggled event just do:
farmSwitch.Toggled += (object sender, ToggledEventArgs e) => {
if(HasBeenProgrammaticallyToggled)
{
//This has been toggled programmatically, so reset our bool
HasBeenProgrammaticallyToggled = false;
}
else
{
// I am assuming this is what you use to determine a manual toggle?
manualOnFarm = true;
}
Console.WriteLine("Switch.Toggled event sent");
changeOnFarmStatus(e);
};
Wouldn't this work?
Use #digitalsa1nt 's suggestion or, use "-=" the method before you switch it manually and use "+=" again.

ToolStripCombobox.SelectionChangeCommitted not found

I have two ToolStripCombobox controls, each with SelectedIndexChanged listeners attached.
I'm facing a problem when I modify the item collection programmatically. I end up triggering the SelectedIndexChanged unwillingly.
When searching online for a solution I found OnSelectionChangeCommitted and the corrensponding event, but Visual studio says:
'System.Windows.Forms.ToolStripComboBox.OnSelectionChangeCommitted(System.EventArgs)' is inaccessible due to its protection level.
If it is impossible to make use of SelectionChangeCommitted, what other ways are there to avoid triggering events when manually updating ToolStripComboBox items?
Im using .Net 4.0 and the ToolStripComboBox is configured with DropDownStyle = DropDownList.
You can access it from underlying ComboBox.
toolStripComboBoxExample.ComboBox.SelectionChangeCommitted += ComboBoxOnSelectionChangeCommitted;
private void ComboBoxOnSelectionChangeCommitted(object o, EventArgs eventArgs)
{
\\Your code goes here.
}
You can do your stuff inside SelectedIndexChanged event itself. By declaring a global bool variable and checking it from SelectedIndexChanged event to verify the type of trigger, you can achieve this. That is something as like,
bool isManualFire = true;
private void Form1_Load(object sender, EventArgs e)
{
//Clear isManualFire flag in case of programatical changes
isManualFire = false;
//Do programatic changes on toolStripComboBox1
//Set it back to get manual triggerings
isManualFire = true;
}
private void toolStripComboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (isManualFire)
{
//DO some operations
}
}
Hope this helps...

How to detect if an event is sent by an argument

I don't know if it is called an argument (i.e. textbox1.text = "Hello";).
I have a control and there is a text box in it. It has a dropdown box that opens when the text is changed. But when I update the text in the text box that box drops down.
I need a way to make it so it only drops down if someone manually does it.
TBAddressBar.ABText.Text = getCurrentBrowser().Source.ToString();
and
public void ABText_TextChanged(object sender, TextChangedEventArgs e)
{
if (sender == 1*)
{
ABDropDown.Visibility = Visibility.Visible;
}
else
{
ABDropDown.Visibility = Visibility.Collapsed;
}
}
If someone manually does it, presumably they are using keypresses to do so. In that case, use KeyDown or KeyUp events to show the dropdown instead.
What I have done in the past is use a boolean variable that I set when I update my textboxes programically to bypass the TextChangedEvent.
i.e.
bool loading;
....
loading =true;
TBAddressBar.ABText.Text = getCurrentBrowser().Source.ToString();
loading = false;
public void ABText_TextChanged(object sender, TextChangedEventArgs e)
{
if(loading) return;
....
}
Simple, just remove the code from your TextChanged Event.
Anyway you got the basic idea.. Now do your dropdown logic in KeyPress event, since it accepts only characters and not the modifiers. So it behaves closer to your requirement. Not that you cant handle the same using KeyDown and KeyUp, you can, but more code..

Modifying ComboBox SelectedIndex Without Triggering Event in C#

My C# application has a comboBox with a SelectedIndexChanged event. Usually, I want this event to fire, but but sometimes I need the event to not fire. My comboBox is an MRU file list. If a file in the list is found to not exist, the item is removed from the comboBox, and the comboBox SelectedIndex is set to zero. However, setting the comboBox SelectedIndex to zero causes the SelectedIndexChanged event to fire, which in this case is problematic because it causes some UIF code to be run in the event handler. Is there a graceful way to disable/enable events for C# form controls? Thanks.
Start the eventhandler method with
ComboBox combo = sender as ComboBox;
if (combo.SelectedIndex == 0)
{
return;
}
If you're issue is with a different eventhandler you could remove the eventhandler's event registration first.
combo.SelectedIndexChanged -= EventHandler<SelectedIndexChangedEventArgs> SomeEventHandler;
combo.SelectedIndex = 0;
combo.SelectedIndexChanged += EventHandler<SelectedIndexChangedEventArgs> SomeEventHandler;
I have encountered this many times over the years. My solution is to have a class level variable called _noise and if I know I am about to change the index of combo or any other similiar control that fires when the selected index changes, I do the following in code.
private bool _noise;
Here is the code for the control event handler
private void cbTest_SelectedIndexChange(object sender, EventArgs e)
{
if (_noise) return;
// process the events code
...
}
Then when I know I am going to change the index, I do the following:
_noise = true; // cause the handler to ignore the noise...
cbTest.Index = value;
_noise = false; // let the event process again
I'm surprised there isn't a better way of doing this, but this is the way I do it. I actually use the Tag field of most controls so I don't have to subclass the control. And I use true/null as the values, since null is the default.
Of course, if you are actually using Tag, you'll need to do it differently...
In handler:
private void control_Event(object sender, EventArgs e)
{
if (control.Tag != null ) return;
// process the events code
...
}
In main code
try
{
control.Tag = true;
// set the control property
control.Value = xxx;
or
control.Index = xxx;
or
control.Checked = xxx;
...
}
finally
{
control.Tag = null;
}
One (fairly ugly) way would be to set a flag in the code that deletes the entry and then check that in the SelectedIndexChanged handler:
if (!deletedEntry)
{
// Do stuff
}
deletedEntry = false;
A better way might be to remove your SelectedIndexChanged event handler at the start of the delete method and reinstate it at the end. This way you code won't know the index has changed.
There's a better way!
combo_box = QComboBox() # your combobox
combo_box.blockSignals(True)
combo_box.setCurrentIndex(self, ix)
combo_box.blockSignals(False)

Is there a BeforeUpdate for a C# ComboBox on a Winform

I come from the VBA world, and remember there was a BeforeUpdate call I could make on a combobox. Now I am in C# (and loving it) and I was wondering is there a BeforeUpdate call for a ComboBox on a Winform?
I can make an invisible textbox and store the info I need there and after the update, look at that box for what I need, but I was hoping there was a simplier solution.
One of the goodies of WF is that you can easily make your own. Add a new class to your project and paste the code below. Compile. Drop the new control from the top of the toolbox onto your form. Implement the BeforeUpdate event.
using System;
using System.ComponentModel;
using System.Windows.Forms;
public class MyComboBox : ComboBox {
public event CancelEventHandler BeforeUpdate;
public MyComboBox() {
this.DropDownStyle = ComboBoxStyle.DropDownList;
}
private bool mBusy;
private int mPrevIndex = -1;
protected virtual void OnBeforeUpdate(CancelEventArgs cea) {
if (BeforeUpdate != null) BeforeUpdate(this, cea);
}
protected override void OnSelectedIndexChanged(EventArgs e) {
if (mBusy) return;
mBusy = true;
try {
CancelEventArgs cea = new CancelEventArgs();
OnBeforeUpdate(cea);
if (cea.Cancel) {
// Restore previous index
this.SelectedIndex = mPrevIndex;
return;
}
mPrevIndex = this.SelectedIndex;
base.OnSelectedIndexChanged(e);
}
finally {
mBusy = false;
}
}
}
You may consider SelectionChangeCommited.
From MSDN:
SelectionChangeCommitted is raised
only when the user changes the combo
box selection. Do not use
SelectedIndexChanged or
SelectedValueChanged to capture user
changes, because those events are also
raised when the selection changes
programmatically.
This won't work when you have set your combobox to allow the user to type in the textbox though. Also, it won't tell you what the 'last' selected item was. You will have to cache this information. However, you don't need to store your information in a textbox. You can use a string.
You could try ValueMemberChanged, Validating, SelectedIndexChanged, or TextChanged. They don't fire like the BeforeUpdate, but you can look at what will be updated and handle the updated, or refuse it.
Out of the box, there's nothing like that. All of the events that deal with change in the combo box happen after the new value is already selected. At that point there's no way to tell what the value USED to be. You're best bet is what you eluded to. As soon as your ComboBox is populated save the SelectedItem to a temporary variable. Then, hook into the SelectedValueChanged event. At that point, your temporary variable will be your old value, and the SelectedItem will be your current value.
private object oldItem = new object();
private void button3_Click(object sender, EventArgs e)
{
DateTime date = DateTime.Now;
for (int i = 1; i <= 10; i++)
{
this.comboBox1.Items.Add(date.AddDays(i));
}
oldItem = this.comboBox1.SelectedItem;
}
private void comboBox1_SelectedValueChanged(object sender, EventArgs e)
{
//do what you need with the oldItem variable
if (oldItem != null)
{
MessageBox.Show(oldItem.ToString());
}
this.oldItem = this.comboBox1.SelectedItem;
}
I think what you wanted was the DropDown event. It will tell you what the value is before the user changes it. However, the user may end up not changing anything, so it's not exactly the same as BeforeUpdate.

Categories