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.
Related
I need show droppeddown combobox after start program.
I need in dropdown style only, not simple style.
This is simple fragment of my program:
private void Form1_Shown(object sender, EventArgs e)
{
CB1.Items.Add("1");
CB1.DropDownStyle = ComboBoxStyle.DropDown;
CB1.DroppedDown = true;
}
But I found the watch sign as cursor till I click on Form in any place.
I guessed that my Form have not fully active state and wait for something.
When I click Form (or combobox or any control) by LBM, it activated fully and all works fine.
Of course the combobox is dropup then, so I need click combobox twice.
Đ•ell me please what is correct initialization of such style combobox without "Cursor = Cursors.Default;"
You can simply wait until cursor is the default:
while (Cursor.Current != Cursors.Default)
{
Application.DoEvents();
}
CB1.Items.Add("1");
CB1.DropDownStyle = ComboBoxStyle.DropDown;
CB1.DroppedDown = true;
Application.DoEvents simply process messages from the window queue, so you can process message until you get that cursor is the default. In that moment, you can drop down your control without problem.
If you prefer, create a extension method for the Form:
public static class FormExtends
{
public static void WaitToDefaultCursor(this Form form)
{
while (Cursor.Current != Cursors.Default)
{
Application.DoEvents();
}
}
}
And use it:
this.WaitToDefaultCursor();
CB1.Items.Add("1");
CB1.DropDownStyle = ComboBoxStyle.DropDown;
CB1.DroppedDown = true;
NOTE: I use Cursor.Default but not to change the cursor. The form is processing messages and it's difficult to select a good moment to drop down the control.
I am trying to disable the thin and crispy checkbox when traditional checkbox is clicked. I have these in a group due to me enabling the whole group when the numericUpDown value is set to 1. When I click traditional checkbox, it doesn't disable the thin and crispy checkbox. I am using windows form application
Code
private void NudQuantity1_ValueChanged(object sender, EventArgs e)
{
if (NudQuantity1.Value == 0)
{
gbCheesePizza.Enabled = false;
}
else
{
gbCheesePizza.Enabled = true;
}
if (CBXTraditional1.Checked == true)
{
CBXthinandcrispy1.Enabled = false;
}
}
When I run this code outside of a groupbox, it works perfectly.
I don't think this block should be inside the event handler
if (CBXTraditional1.Checked == true)
{
CBXthinandcrispy1.Enabled = false;
}
It means that, provided you've got no other event handling for the checkboxes, this code will only be executed when you change the value of NudQuantity1 so it won't execute anything when you click the checkboxes afterwards.
Try use radio buttons as Steve mentioned. They do this for you.
I have a CheckBox that is set to CheckState.Indeterminate. When a timer expires it will be set to CheckState.Unchecked and turn off an external output signal. So far so good.
With the current code when the user clicks on the Indeterminate CheckBox it will become an Unchecked CheckBox. I would like to intercept it and make it a Checked CheckBox.
The effect for the user would be to cancel the timer and leave the output on until the user unchecks the box or the user starts a separate process that takes over and the Indeterminate CheckBox` is set again.
As it is he turns off the output and has to explicitly turn it on again.
I tried the validating event, but that doesn't happen until I leave the box.
Update 1: To clarify a little bit what the user wants to see.
When the lights are off the box is always unchecked.
When the automated part of the system is running, the light is on. If the user looks at the control it is in the indeterminate state because the user did not activate it it, but it is on.
When the process stops a timer is started leaving the lights on for 2 minutes. The user still sees the indeterminate state during this time.
If the user needs the light to remain on he will check the box removing the indeterminate state. When he is through he will manually uncheck the box turning off the light or restart the automated process which will make it indeterminate again.
I wasn't aware of the AutoCheck property
There is no need for anything drastic, you just don't like the way that Checkbox implemented its AutoCheck property. So select the control and set its AutoCheck property to False. That let's you control the check state the way you want it.
Add the Click event handler to allow the user to flip the state straight from Indeterminate to Checked with a mouse click or spacebar press:
private void checkBox1_Click(object sender, EventArgs e) {
checkBox1.CheckState = checkBox1.CheckState == CheckState.Checked ?
CheckState.Unchecked : CheckState.Checked;
}
I'm advising against changing the behavior of standard controls, but if this is what you need, you can subclass the CheckBox and override the Onclick method.
This is where you can see what the standard behavior is.
All you need to do is rework that logic in the switch statement and call the base. We need to suppress the base's checkstate logic by setting AutoCheck to false, then restore it to its previous value afterwards:
public class MyCheckBox : CheckBox
{
protected override void OnClick(EventArgs e)
{
if (AutoCheck)
switch (CheckState)
{
case CheckState.Indeterminate:
CheckState = CheckState.Checked;
break;
case CheckState.Unchecked:
if (ThreeState)
{
CheckState = CheckState.Indeterminate;
}
else
{
CheckState = CheckState.Checked;
}
break;
default:
CheckState = CheckState.Unchecked;
break;
}
var oldAutoCheckValue = AutoCheck;
AutoCheck = false;
base.OnClick(e);
AutoCheck = oldAutoCheckValue;
}
}
As an alternative solution, you should consider using radio buttons to improve UX.
I think you need CheckStateChanged event.
Try this and let me know:
//mark the process as running (check box is Indeterminate state)
private bool processIsRunning = true;
private void chkState_CheckStateChanged(object sender, EventArgs e)
{
//the user clicks the indeterminate checkbox
if (processIsRunning && chkState.CheckState == CheckState.Unchecked)
{
processIsRunning = false;
chkState.CheckState = CheckState.Checked;
}
}
I am working on a pretty basic C# visual studio forms application but am having some issue getting the track bar to act as I want it to so hoping someone in the community might have a solution for this.
What I have is a pretty basic application with the main part being a track bar with a value of 0 to 100. The user sets the value of the track to represent "the amount of work to perform" at which point the program reaches out to some devices and tells them to do "x" amount of work (x being the value of the trackbar). So what I do is use the track bars scroll event to catch when the track bars value has changed and inside the handler call out to the devices and tells them how much work to do.
My issue is that my event handler is called for each value between where the track bar currently resides and where ever it ends. So if it is slid from 10 to 30, my event handler is called 20 times which means I am reaching out to my devices and telling them to run at values I don't even want them to run at. Is there someway only to event when scroll has stopped happening so you can check the final value?
Just check a variable, if the user clicked the track bar. If so, delay the output.
bool clicked = false;
trackBar1.Scroll += (s,
e) =>
{
if (clicked)
return;
Console.WriteLine(trackBar1.Value);
};
trackBar1.MouseDown += (s,
e) =>
{
clicked = true;
};
trackBar1.MouseUp += (s,
e) =>
{
if (!clicked)
return;
clicked = false;
Console.WriteLine(trackBar1.Value);
};
For the problem #roken mentioned, you can set LargeChange and SmallChange to 0.
Try the MouseCaptureChanged event - that is the best for this task
A user could also move the track bar multiple times in a short period of time, or click on the track multiple times to increment the thumb over instead of dragging the thumb. All being additional cases where the value that registers at the end of a "thumb move" is not really the final value your user desires.
Sounds like you need a button to confirm the change, which would then capture the current value of the trackbar and send it off to your devices.
Try this with the trackbar_valuechanged event handler:
trackbar_valuechanged(s,e) {
if(trackbar.value == 10){
//Do whatever you want
} else{
//Do nothing or something else
}
}
I found a fairly reliable way to do this is to use a timer hooked up in the trackbar.Scroll event:
private Timer _scrollingTimer = null;
private void trackbar_Scroll(object sender, EventArgs e)
{
if (_scrollingTimer == null)
{
// Will tick every 500ms (change as required)
_scrollingTimer = new Timer()
{
Enabled = false,
Interval = 500,
Tag = (sender as TrackBar).Value
};
_scrollingTimer.Tick += (s, ea) =>
{
// check to see if the value has changed since we last ticked
if (trackBar.Value == (int)_scrollingTimer.Tag)
{
// scrolling has stopped so we are good to go ahead and do stuff
_scrollingTimer.Stop();
// Do Stuff Here . . .
_scrollingTimer.Dispose();
_scrollingTimer = null;
}
else
{
// record the last value seen
_scrollingTimer.Tag = trackBar.Value;
}
};
_scrollingTimer.Start();
}
}
I had this problem just now as I'm implementing a built in video player and would like the user to be able to change the position of the video but I didn't want to overload the video playback API by sending it SetPosition calls for every tick the user passed on the way to his/her final destination.
This is my solution:
First, the arrow keys are a problem. You can try your best to handle the arrow keys via a timer or some other mechanism but I found it more pain than it is worth. So set the property SmallChange and LargeChange to 0 as #Matthias mentioned.
For mouse input, the user is going to have to click down, move it, and let go so handle the MouseDown, MouseUp, and the Scroll events of the trackbar like so:
private bool trackbarMouseDown = false;
private bool trackbarScrolling = false;
private void trackbarCurrentPosition_Scroll(object sender, EventArgs e)
{
trackbarScrolling = true;
}
private void trackbarCurrentPosition_MouseUp(object sender, MouseEventArgs e)
{
if (trackbarMouseDown == true && trackbarScrolling == true)
Playback.SetPosition(trackbarCurrentPosition.Value);
trackbarMouseDown = false;
trackbarScrolling = false;
}
private void trackbarCurrentPosition_MouseDown(object sender, MouseEventArgs e)
{
trackbarMouseDown = true;
}
I had a similar problem, only with a range TrackBar Control. Same idea applies to this also, only it's easier for this case.
I handled the MouseUp Event on the TrackBar to launch the procedures I needed, only after you would let go of the mouse button. This works if you drag the bar to your desired position or just click it.
private void rangeTrackBarControl1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
{
YourProcedureHere();
}
i solved the problem for my application with two events:
catch the Trackbar-ValueChange-Event
whithin the value-change event disable the valuechange event and enable the MouseUp-Event
public MainWindow()
{
//Event for new Trackbar-Value
trackbar.ValueChanged += new System.EventHandler(trackbar_ValueChanged);
}
private void trackbar_ValueChanged(object sender, EventArgs e)
{
//enable Trackbar Mouse-ButtonUp-Event
trackbar.MouseUp += ch1_slider_MouseUp;
//disable Trackbar-ValueChange-Event
trackbar.ValueChanged -= ch1_slider_ValueChanged;
}
private void trackbar_MouseUp(object sender, EventArgs e)
{
//enable Trackbar-ValueChange-Event again
trackbar.ValueChanged += new System.EventHandler(trackbar_ValueChanged);
//disable Mouse-ButtonUp-Event
trackbar.MouseUp -= trackbar_MouseUp;
//This is the final trackbar-value
textBox.AppendText(trackbar.Value);
}
ATTENTION: this works if the trackbar is moved by mose. It is also possible to move the trackbar by keyboard. Then futher code must be implemented to handle this event.
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.