Panel radio buttons selection 1 and change other panel radio buttons ? c# - c#

i want to make trafic app for that i have to switch between radio button that act like a signals, actually i have 4 panels every panel have 3 radio buttons red , green , orange
Problem: when i select red in any panel or green other radio buttons must set1 to green or red according to requirment
Remember their will be only 1 green and all other reds at same time
i tried to implement code in check change event but if i apply the code on every button this become recursive so create problem i tried that too but not suitable solution
1 event on every radio button
private void R_lane3Red_CheckedChanged(object sender, EventArgs e)
{
// var checkedButton2 = panel2.Controls.OfType<RadioButton>()
// .FirstOrDefault(r => r.Checked);
// var checkedButton1 = panel1.Controls.OfType<RadioButton>()
// .FirstOrDefault(r => r.Checked);
// var checkedButton3 = panell3.Controls.OfType<RadioButton>()
// .FirstOrDefault(r => r.Checked);
// var checkedButton4 = panell4.Controls.OfType<RadioButton>()
// .FirstOrDefault(r => r.Checked);
//if (checkedButton2.Name.Contains("Green")){
// R_lane1Red.Checked = true;
// R_lane4Red.Checked = true;
// R_lane3Red.Checked = true;
//}
//if (checkedButton1.Name.Contains("Green"))
//{
// R_lane2Red.Checked = true;
// R_lane4Red.Checked = true;
// R_lane3Red.Checked = true;
//}
//if (checkedButton3.Name.Contains("Green"))
//{
// R_lane2Red.Checked = true;
// R_lane4Red.Checked = true;
// R_lane1Red.Checked = true;
//}
//if (checkedButton4.Name.Contains("Green"))
//{
// R_lane2Red.Checked = true;
// R_lane3Red.Checked = true;
// R_lane1Red.Checked = true;
//}
below is image of panel and radio buttons
image of UI

I suggest creating your Traffic Lights as a control. Then you can build the rules into the traffic light control for how it should behave when a specific light is set. Something like the following may work for you:
// The event that fires when a light changed, sends notification to the main form.
public delegate void LightChangedHandler(object sender, Lights light);
// Simple enum to pass the state of the TrafficLight around.
public enum Lights
{
Green,
Orange,
Red
}
public partial class TrafficLights : UserControl
{
public event LightChangedHandler LightChanged;
protected virtual void OnChanged(Lights light)
{
if (LightChanged != null)
{
LightChanged(this, light);
}
}
private bool _changing = false;
public TrafficLights()
{
InitializeComponent();
}
// The business rules for the Traffic Light states.
public void SetLight(Lights light)
{
if (_changing)
{
return;
}
_changing = true;
switch (light)
{
case Lights.Green:
radioGreen.Checked = true;
radioOrange.Checked = false;
radioRed.Checked = false;
break;
case Lights.Orange:
radioOrange.Checked = true;
radioGreen.Checked = false;
radioRed.Checked = false;
break;
case Lights.Red:
radioRed.Checked = true;
radioGreen.Checked = false;
radioOrange.Checked = false;
break;
}
OnChanged(light);
_changing = false;
}
private void radioGreen_CheckedChanged(object sender, EventArgs e)
{
SetLight(Lights.Green);
}
private void radioOrange_CheckedChanged(object sender, EventArgs e)
{
SetLight(Lights.Orange);
}
private void radioRed_CheckedChanged(object sender, EventArgs e)
{
SetLight(Lights.Red);
}
}
Then you can add as many TrafficLights as you want to your main form. When a light changes in any of your traffic lights, its raises an event to the main form. You can then handle this event and apply the business rules for how the bank of traffic lights should behave. Something like this:
private readonly List<TrafficLights> _trafficLights = new List<TrafficLights>();
private bool _changing = false;
public Form1()
{
InitializeComponent();
// Add each TrafficLight control on the Form to a list so we can spin through them later and set their state.
_trafficLights.Add(trafficLights1);
_trafficLights.Add(trafficLights2);
_trafficLights.Add(trafficLights3);
_trafficLights.Add(trafficLights4);
// Add the handler for the LightChanged event of each TrafficLight.
this.trafficLights1.LightChanged += TrafficLightsOnLightChanged;
this.trafficLights2.LightChanged += TrafficLightsOnLightChanged;
this.trafficLights3.LightChanged += TrafficLightsOnLightChanged;
this.trafficLights4.LightChanged += TrafficLightsOnLightChanged;
}
private void TrafficLightsOnLightChanged(object sender, Lights light)
{
// Only allow the first LightChanged event to fire off to avoid the recursive events.
if (_changing)
{
return;
}
_changing = true;
TrafficLights currentLight = sender as TrafficLights;
// Set the Light state of all other TrafficLights.
foreach (TrafficLights trafficLight in _trafficLights
.Where(trafficLight => trafficLight != currentLight))
{
LightChanged(trafficLight, light);
}
_changing = false;
}
// The business rules for setting the other TrafficLight states.
private static void LightChanged(TrafficLights trafficLight, Lights light)
{
// You will need to adjust the following to suit your specific business rules.
switch (light)
{
case Lights.Green:
trafficLight.SetLight(Lights.Red);
break;
case Lights.Orange:
trafficLight.SetLight(Lights.Orange);
break;
case Lights.Red:
trafficLight.SetLight(Lights.Green);
break;
}
}
Adding the bool _changing variable allows you to stop the event from recursively occurring. When the first event is fired, you set the _changing to true. This will stop further events from firing until you set it back to false once you are done handling the first event.

Related

How can i toggle the same button click event for two cases?

private void btnRecord_Click(object sender, EventArgs e)
{
FFmpeg_Capture record = new FFmpeg_Capture();
record.Start("Testing", 60);
}
What i want to do is when i click the button it will change the text of it to "Stop" then when i click again it will do the code :
record.Stop();
and will change the text of the button back to "Record" so i can use the same button to start/stop.
The simplest way may be to introduce the flag which will store the current player state. For just a play/stop this flag may be bool, for more states e.g. play/pause/stop it may be enum. Then you can use this flag to determine the current state and change it accordingly
bool playing = false;
FFmpeg_Capture record = new FFmpeg_Capture();
private void btnRecord_Click(object sender, EventArgs e)
{
if(playing)
{
record.Stop();
playing = false;
btnRecord.Text = "Play";
}
else
{
record.Start("Testing", 60);
btnRecord.Text = "Stop";
playing = true;
}
}
The problem here that you may have other ways to change player's state (for example, by click on the player itself) and thus you will need to maintain the playing flag in all such a places to be in sync with real player state.
So, the better way will be to check the player itself for state (if the player has such an API). I assumed that player has the State property which is enum and this property represtnts the current state. In this case the code may be following. I do not know if the real player has such a property or not, so this is just a idea.
FFmpeg_Capture record = new FFmpeg_Capture();
private void btnRecord_Click(object sender, EventArgs e)
{
if(record.State is CaptureState.Playing)
{
record.Stop();
btnRecord.Text = "Play";
}
else
{
record.Start("Testing", 60);
btnRecord.Text = "Stop";
}
}
Add a bool for the current button state.
if(button_state)
{
FFmpeg_Capture record = new FFmpeg_Capture();
record.Start("Testing", 60);
button_state != button_state;
btnRecord.Text = "Stop";
}
else
{
record.Stop();
btnRecord.Text = "Record"
button_state != button_state;
}

Button.Enabled not working on first of several buttons in BackgroundWorker

I have several buttons that I want turned off/on at different times. I put these into a function for simplicity. Enabling the buttons is called by a BackgroundWorker so that I can update a camera view at the same time as listening to a Serial port for an 'enable' signal. Disabling the controls is called by the button click, while enable is handled by the BackgroundWorker (it watches for the Serial port signal). All buttons re-enable, except for the first one listed in enableControls();. If I change the order of enableControls() then the button at top is left disabled. What is causing this? I would think that either all buttons or no buttons would be re-enabled.
private void btnLeft_Click(object sender, EventArgs e) // All buttons are similar, just different output to port
{
disableControls();
hardWorker.RunWorkerAsync();
int stepSize = Convert.ToInt32(ddStepSize.Text);
string outString;
if (moveSampHome == false)
{
outString = "#MOVER" + stepSize;
posX = posX - RcDrawSlide.Width * stepSize / (1000 * Convert.ToInt32(slideSizeX));
}
else { outString = "#MSMPR" + stepSize; }
port.Write(outString + "\n");
}
private void hardWorker_DoWork(object sender2, DoWorkEventArgs f)
{
arduinoIn = "0";
for (int i = 0; i == 0;)
{
if (arduinoIn != null)
{
if (arduinoIn.Contains("1"))
{
i = 1;
arduinoIn = "0";
}
}
}
port.Write("1");
}
private void hardWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
enableControls();
}
private void enableControls()
{
btnBack.Enabled = true; // Swap this for any other button - that one will not be enabled.
btnForward.Enabled = true;
btnLeft.Enabled = true;
btnRight.Enabled = true;
}
private void disableControls()
{
btnBack.Enabled = false;
btnForward.Enabled = false;
btnLeft.Enabled = false;
btnRight.Enabled = false;
}
If I add a button that runs enableControls() on click everything is reenabled, so I know this is due to having it run from a BackgroundWorker. I think that BackgroundWorker is necessary, though. I'm just unsure why it's only the first btn.Enabled = true; that doesn't work. Is there a workaround for this?
For hardWorker_DoWork() try something more like:
private void hardWorker_DoWork(object sender2, DoWorkEventArgs f)
{
arduinoIn = "0";
while (arduino == null || !arduinoIn.Contains("1")) {
System.Threading.Thread.Sleep(0); // or try a SMALL number like 50!
}
arduinoIn = "0";
port.Write("1");
}
Is it possible the buttons are being enabled again when data is received on the port? You haven't shown any code relating to that side...

ToolStripDropDown catches MouseeDown before underlying control

I have created my own ComboBox-like control where the dropdown part contains a tree. I have seen those solutions using an ordinary ComboBox and overwriting the WndProc, but there was always some odd behavior despite lots and lots of code. So I decided to make it simple: just a label with a ToolStripDropDown/ToolStripControlHost that is opened when mouse goes down on the label. The missing ComboBox triangle doesn't hurt.
Everything works perfectly, except one tiny thing: like with the stock ComboBox I would like the dropdown to hide when I click on the label again. But when I click on it, the dropdown hides for a split second, just to appear again. If I click outside the label, the dropdown just hides, like it should be.
public class RepoNodeComboBox: Label
{
RepoTreeView repoTreeView;
ToolStripControlHost treeViewHost;
ToolStripDropDown dropDown;
bool isDropDownOpen;
public int DropDownHeight;
public RepoNodeComboBox()
{
repoTreeView = new RepoTreeView();
repoTreeView.BorderStyle = BorderStyle.None;
repoTreeView.LabelEdit = false;
treeViewHost = new ToolStripControlHost(repoTreeView);
treeViewHost.Margin = Padding.Empty;
treeViewHost.Padding = Padding.Empty;
treeViewHost.AutoSize = false;
dropDown = new ToolStripDropDown();
dropDown.CanOverflow = true;
dropDown.AutoClose = true;
dropDown.DropShadowEnabled = true;
dropDown.Items.Add(treeViewHost);
dropDown.Closing += dropDownClosing;
TextAlign = ContentAlignment.MiddleLeft;
BackColor = SystemColors.Window;
BorderStyle = BorderStyle.FixedSingle;
DropDownHeight = 400;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (dropDown != null)
{
dropDown.Dispose();
dropDown = null;
}
}
base.Dispose(disposing);
}
// when mouse goes down on the label, this is executed first
void dropDownClosing(object sender, System.ComponentModel.CancelEventArgs e)
{
// just to test if I can get more out of it than with dropdown.Visible
isDropDownOpen = false;
}
// this is subsidiary to the Closing event of the dropdown
protected override void OnMouseDown(MouseEventArgs e)
{
if (dropDown != null)
{
if (isDropDownOpen)
{
dropDown.Hide();
}
else
{
repoTreeView.Size = new Size(Width, DropDownHeight);
treeViewHost.Width = Width;
treeViewHost.Height = DropDownHeight;
dropDown.Show(this, 0, Height);
isDropDownOpen = true;
}
}
base.OnMouseDown(e);
}
}
As far as I can see (breakpoints), the dropdown catches the MOUSEDOWN event first in order to close itself. Only after that my label gets passed through the MOUSEDOWN event, and since it sees the dropdown is closed, it thinks the label has been clicked like for the first time - and opens the dropdown again.
So it seems the label has no chance of knowing if the MOUSEDOWN was the result of closing the dropdown item. I could open it every other event, but that would require no other closing events to happen.
Is there any way to make sure that an open dropdown item just closes even if I click on the label?
Try checking for the Mouse position when the floating host closes:
void dropDownClosing(object sender, CancelEventArgs e) {
isDropDownOpen = this.ClientRectangle.Contains(this.PointToClient(Control.MousePosition));
}
On the MouseDown code, make sure to set isDropDownOpen to false in the true block:
protected override void OnMouseDown(MouseEventArgs e) {
if (dropDown != null) {
if (isDropDownOpen) {
isDropDownOpen = false;
dropDown.Hide();
} else {
isDropDownOpen = true;
repoTreeView.Size = new Size(Width, DropDownHeight);
treeViewHost.Width = Width;
treeViewHost.Height = DropDownHeight;
dropDown.Show(this, 0, Height);
}
}
base.OnMouseDown(e);
}

c# - Multiple panel form - ComboBox handler stops working when going to next panel and back to previous

I created a multiple panel form using the Visual Studios Designer. The form is used to save Items to a database. The user adds information about the item in the first form then selects next to add pictures to the item. Different items have different numbers of pictures associated with them.
The transitions of the panels are as follows:
Panel1 <--> Panel2a
Panel1 <--> Panel2b
Panel1 <--> Panel2c
Panel1 <--> Panel2d
So for any given item, there are two panels to fill out. There are 4 versions of the second panel which determines how many picture boxes and "Browse" buttons there are.
A ComboBox on panel1 determines which version of panel2 is selected. A "next" button is used to move on to panel2 and a "previous" button switches back to panel1.
The code is as follows:
public partial class formAddItem : Form
{
// To browse for images
OpenFileDialog mImageBrowse = new OpenFileDialog();
// store image paths
string mImagePath1 = null;
string mImagePath2 = null;
// Constructor
public formAddItem()
{
InitializeComponent();
}
private void frmAddItem_Load(object sender, EventArgs e)
{
// Retrieve list of items from database, store in dataset
// ...
// List to use as DataSource
List<string> listItemType = new List<string>();
// Add items from dataset to a list and alter string for readability
foreach (ITEM_TYPERow itemTypeRow in mDataSet.ITEM_TYPE)
{
listItemType.Add("ITEM_" + itemTypeRow[0]);
}
comboItemType.DataSource = listItemType;
// set up current state
panel1.Visible = true;
panel1.BringToFront();
panel1.Focus();
btnNext.Enabled = true;
btnPrevious.Enabled = false;
}
private void btnNext_Click(object sender, EventArgs e)
{
// Next panel depends on item type selection
string itemTypeSelection = comboItemType.Text;
switch (elementTypeSelection)
{
case "ITEM_A":
panel2A.Visible = true;
panel2A.BringToFront();
panel2A.Focus();
break;
case "ITEM_B":
panel2B.Visible = true;
panel2B.BringToFront();
panel2B.Focus();
break;
case "ITEM_C":
panel2C.Visible = true;
panel2C.BringToFront();
panel2C.Focus();
break;
case "ITEM_D":
panel2D.Visible = true;
panel2D.BringToFront();
panel2D.Focus();
break;
default:
return;
}
// Set current state
btnNext.Enabled = false;
btnPrevious.Enabled = true;
}
private void btnPrevious_Click(object sender, EventArgs e)
{
btnPrevious.Enabled = false;
btnNext.Enabled = true;
panel1.Visible = true;
panel1.BringToFront();
panel1.Focus();
}
private void btnItemA1Browse_Click(object sender, EventArgs e)
{
// Set filter
mImageBrowse.Filter = "png files (*.png)|*.png";
mImageBrowse.FilterIndex = 1;
DialogResult userCickedOk = mImageBrowse.ShowDialog();
if (userCickedOk == DialogResult.OK)
{
mImagePath1 = mImageBrowse.SafeFileName;
pictureBoxItemA1.Image = new Bitmap(mImageBrowse.FileName);
}
}
private void btnItemA2Browse_Click(object sender, EventArgs e)
{
// Set filter
mImageBrowse.Filter = "png files (*.png)|*.png";
mImageBrowse.FilterIndex = 1;
DialogResult userCickedOk = mImageBrowse.ShowDialog();
if (userCickedOk == DialogResult.OK)
{
mImagePath2 = mImageBrowse.SafeFileName;
pictureBoxItemA2.Image = new Bitmap(mImageBrowse.FileName);
}
}
// Resets image stuff when a new item type is selected
private void comboItemType_SelectionChangeCommitted(object sender, EventArgs e)
{
// Clear images and image paths
mImagePath1 = null;
mImagePath2 = null;
...
pictureBoxItemA1.InitialImage = null;
pictureBoxItemA2.InitialImage = null;
...
}
}
The comboItemType_SelectionChangeCommitted() seems to work when I press 'next' and then 'previous' if I don't browse for an image. But as soon as I browse, things stop working.
There are some other things going on but I am hoping they aren't relevant to my problem
Look at changes I made to method below. Button Next should display next panel (not current).
private void btnNext_Click(object sender, EventArgs e)
{
// Next panel depends on item type selection
string itemTypeSelection = comboItemType.Text;
switch (elementTypeSelection)
{
case "ITEM_A":
panel2B.Visible = true;
panel2B.BringToFront();
panel2B.Focus();
elementTypeSelection = "ITEM_B";
break;
case "ITEM_B":
panel2C.Visible = true;
panel2C.BringToFront();
panel2C.Focus();
elementTypeSelection = "ITEM_C";
break;
case "ITEM_C":
panel2D.Visible = true;
panel2D.BringToFront();
panel2D.Focus();
elementTypeSelection = "ITEM_D";
btnNext.Enabled = false;
break;
case "ITEM_D":
break;
default:
return;
}
}

Timer, click, mousedown, mouseup events not working together

Looking for some help on a problem Im having
sorry if this question has already been asked, I can not find anything similar.
The idea is when a picturebox is clicked changed the image to ON.
If the picture box is held for more than 2 seconds to open a new form and leave the picturebox as OFF.
However if the picturebox is clicked ON and then held for 2 seconds and then returns i need the picturebox state to remain ON.
Here is what I have tried so far.
I believe for this to work correctly I need to stop MouseUp event from occuring.
Is there a way I can stop MouseUp when Tick occurs?
Is there a easier / better way to do this?
Any help would be appreciated.
private void time_HoldDownInternal_Tick(object sender, EventArgs e)
{
time_HoldDownInternal.Enabled = false;
time_HoldDownInternal.Interval = 1000;
form1show.Visible = true;
}
private void pb_pictureBoxTest_MouseDown(object sender, MouseEventArgs e)
{
mainMenuVariables.mousedown = true;
time_HoldDownInternal.Enabled = true;
}
private void pb_pictureBoxTest_MouseUp(object sender, MouseEventArgs e)
{
mainMenuVariables.mousedown = false;
//MessageBox.Show("mouse up");
time_HoldDownInternal.Enabled = false;
time_HoldDownInternal.Interval = 1000;
}
private void pb_pictureBoxTest_Click(object sender, EventArgs e)
{
if (mainMenuVariables.mousedown == true)
{
if (mainMenuVariables.pictureBox == false)
{
mainMenuVariables.pictureBox = true;
pb_pictureBoxTest.Image = new Bitmap(mainMenuVariables.pictureBoxOn);
return;
}
if (mainMenuVariables.pictureBox == true)
{
mainMenuVariables.pictureBox = false;
pb_pictureBoxTest.Image = new Bitmap(mainMenuVariables.pictureBoxOff);
return;
}
}
if (mainMenuVariables.mousedown == false)
{
//nothing
}
}
Rather than starting a timer, just record the current time on mouse down. Then in mouse up, check if it has been 2 seconds. e.g:
private void pb_pictureBoxTest_MouseDown(object sender, MouseEventArgs e)
{
mainMenuVariables.mousedown = true;
mainMenuVariables.mousedowntime = DateTime.Now;
}
private void pb_pictureBoxTest_MouseUp(object sender, MouseEventArgs e)
{
mainMenuVariables.mousedown = false;
var clickDuration = DateTime.Now - mainMenuVariables.mousedowntime;
if ( clickDuration > TimeSpan.FromSeconds(2))
{
// Do 'hold' logic (e.g. open dialog, etc)
}
else
{
// Do normal click logic (e.g. toggle 'On'/'Off' image)
}
}

Categories