How to make the event wait until a boolean is changed - c#

I have an event registered.
layout.SizeChanged += parentToggleBox.Resize;
Problem is, I would like this Resize event to wait until my mouse has moved away from the box.
How to make this event wait until a boolean is changed from false to true?
or wait until OnMouseLeave(object sender, MouseEventArgs e) is triggered?

Here's an example that I put together:
public class Form1 : Form
{
private Panel Panel1;
private Label Label1;
public Form1()
{
this.Panel1 = new Panel()
{
BackColor = System.Drawing.Color.Red,
};
this.Label1 = new Label()
{
Top = 200,
Text = "Click",
};
bool clicked = false;
bool entered = false;
this.Panel1.Click += (s, e) =>
{
this.Panel1.BackColor = System.Drawing.Color.Blue;
clicked = true;
};
this.Panel1.MouseEnter += (s, e) =>
{
this.Panel1.BackColor = System.Drawing.Color.Yellow;
clicked = false;
entered = true;
};
this.Panel1.MouseLeave += (s, e) =>
{
if (entered && clicked)
{
this.Panel1.BackColor = System.Drawing.Color.Green;
this.Label1.Text = "Success";
}
};
this.Controls.Add(this.Panel1);
this.Controls.Add(this.Label1);
}
}
I've used a Click event rather than a Resize to demonstrate the technique.
Effectively this is just setting two booleans and when the right combination of entered and clicked occurs then the code in the block that contains this.Label1.Text = "Success"; will run.
The colours are set for debugging purposes.
To run, do this:
var form1 = new Form1();
form1.ShowDialog();

Related

Why can not I place my custom textbox inside a panel or groupBox?

I have a custom TextBox control defined as follows:
class PHTextBox : System.Windows.Forms.TextBox
{
System.Drawing.Color DefaultColor;
public string PlaceHolderText { get; set; }
public PHTextBox(string placeholdertext)
{
// get default color of text
DefaultColor = this.ForeColor;
// Add event handler for when the control gets focus
this.GotFocus += (object sender, EventArgs e) =>
{
this.Text = String.Empty;
this.ForeColor = DefaultColor;
};
// add event handling when focus is lost
this.LostFocus += (Object sender, EventArgs e) => {
if (String.IsNullOrEmpty(this.Text) || this.Text == PlaceHolderText)
{
this.ForeColor = System.Drawing.Color.Gray;
this.Text = PlaceHolderText;
}
else
{
this.ForeColor = DefaultColor;
}
};
if (!string.IsNullOrEmpty(placeholdertext))
{
// change style
this.ForeColor = System.Drawing.Color.Gray;
// Add text
PlaceHolderText = placeholdertext;
this.Text = placeholdertext;
}
}
}
I am trying to add a custom textBox in the following way to a Panel:
this.tbNombresClienteConfirmarPago = new PHTextBox("Your name");
this.tbNombresClienteConfirmarPago.Location = new System.Drawing.Point(0,0);//(644, 485);
this.tbNombresClienteConfirmarPago.Name = "tbNombresClienteConfirmarPago";
this.tbNombresClienteConfirmarPago.Size = new System.Drawing.Size(203, 20);
this.tbNombresClienteConfirmarPago.TabIndex = 7;
this.tbNombresClienteConfirmarPago.MaxLength = 50;
this.panel1.Controls.Add(this.tbNombresClienteConfirmarPago);
But it does not work.
I add a textBox or a button that belong to Windows Forms and they are added correctly to the Panel without problems.
Any comment is welcomed.
Upgrade:
When I wanted to say that 'It doesn't work' I was referring to the fact that the object is not displayed inside the Panel.
A PHTextBox is displayed correctly within the form.

c# - disable events during MouseDoubleClick

Is it possible to disable other MouseEvent during a MouseDoubleClick event?
I've registered multiple events on a label but i want MouseDoubleClick is prioritary and block all other MouseEvent (es. MouseDown or MuoseMove). Then, after the DoubleClickHandler is finished i want to reactivate them.
You can create a flag to store your different states in order for your methods to know what they have to know.
A simple approach will be something like:
bool dblClickDone = false;
void DoubleClickHandler(...)
{
//...
dblClickDone = true;
}
void MouseDownHandler(...)
{
if (dblClickDone) {
//...
}
}
You get the idea.
Just unregister the events using "-=", example:
private void OnMouseDoubleClick(object sender, MouseEventArgs e)
{
this.MouseDown -= MethodOnMouseDown;
this.MouseMove -= MethodOnMouseMove;
// Do something.....
this.MouseDown += MethodOnMouseDown;
this.MouseMove += MethodOnMouseMove;
}
MSDN suggests two methods. The one you use will be based on the design of you program. I've copied the code from MSDN below in case the page goes down.
First method is to rollback any changes made that were made in the 'single click' event if the double click event is fired.
using System;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace MouseRollBackSingleClick
{
public class Form1 : Form
{
private DoubleClickButton button1;
private FormBorderStyle initialStyle;
public Form1()
{
initialStyle = this.FormBorderStyle;
this.ClientSize = new System.Drawing.Size(292, 266);
button1 = new DoubleClickButton();
button1.Location = new Point (40,40);
button1.Click += new EventHandler(button1_Click);
button1.AutoSize = true;
this.AllowDrop = true;
button1.Text = "Click or Double Click";
button1.DoubleClick += new EventHandler(button1_DoubleClick);
this.Controls.Add(button1);
}
// Handle the double click event.
void button1_DoubleClick(object sender, EventArgs e)
{
// Change the border style back to the initial style.
this.FormBorderStyle = initialStyle;
MessageBox.Show("Rolled back single click change.");
}
// Handle the click event.
void button1_Click(object sender, EventArgs e)
{
this.FormBorderStyle = FormBorderStyle.FixedToolWindow;
}
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.Run(new Form1());
}
}
public class DoubleClickButton : Button
{
public DoubleClickButton() : base()
{
// Set the style so a double click event occurs.
SetStyle(ControlStyles.StandardClick |
ControlStyles.StandardDoubleClick, true);
}
}
}
The second method is to create a timer which triggers when the single click is performed. If a double click is not followed within the timer limit, it's assumed the user wants to perform a single click and that action is taken, otherwise the double click action is taken.
using System;
using System.Drawing;
using System.Windows.Forms;
namespace SingleVersusDoubleClick
{
class Form1 : Form
{
private Rectangle hitTestRectangle = new Rectangle();
private Rectangle doubleClickRectangle = new Rectangle();
private TextBox textBox1 = new TextBox();
private Timer doubleClickTimer = new Timer();
private ProgressBar doubleClickBar = new ProgressBar();
private Label label1 = new Label();
private Label label2 = new Label();
private bool isFirstClick = true;
private bool isDoubleClick = false;
private int milliseconds = 0;
[STAThread]
public static void Main()
{
Application.EnableVisualStyles();
Application.Run(new Form1());
}
public Form1()
{
label1.Location = new Point(30, 5);
label1.Size = new Size(100, 15);
label1.Text = "Hit test rectangle:";
label2.Location = new Point(30, 70);
label2.Size = new Size(100, 15);
label2.Text = "Double click timer:";
hitTestRectangle.Location = new Point(30, 20);
hitTestRectangle.Size = new Size(100, 40);
doubleClickTimer.Interval = 100;
doubleClickTimer.Tick +=
new EventHandler(doubleClickTimer_Tick);
doubleClickBar.Location = new Point(30, 85);
doubleClickBar.Minimum = 0;
doubleClickBar.Maximum = SystemInformation.DoubleClickTime;
textBox1.Location = new Point(30, 120);
textBox1.Size = new Size(200, 100);
textBox1.AutoSize = false;
textBox1.Multiline = true;
this.Paint += new PaintEventHandler(Form1_Paint);
this.MouseDown += new MouseEventHandler(Form1_MouseDown);
this.Controls.AddRange(new Control[] { doubleClickBar, textBox1,
label1, label2 });
}
// Detect a valid single click or double click.
void Form1_MouseDown(object sender, MouseEventArgs e)
{
// Verify that the mouse click is in the main hit
// test rectangle.
if (!hitTestRectangle.Contains(e.Location))
{
return;
}
// This is the first mouse click.
if (isFirstClick)
{
isFirstClick = false;
// Determine the location and size of the double click
// rectangle area to draw around the cursor point.
doubleClickRectangle = new Rectangle(
e.X - (SystemInformation.DoubleClickSize.Width / 2),
e.Y - (SystemInformation.DoubleClickSize.Height / 2),
SystemInformation.DoubleClickSize.Width,
SystemInformation.DoubleClickSize.Height);
Invalidate();
// Start the double click timer.
doubleClickTimer.Start();
}
// This is the second mouse click.
else
{
// Verify that the mouse click is within the double click
// rectangle and is within the system-defined double
// click period.
if (doubleClickRectangle.Contains(e.Location) &&
milliseconds < SystemInformation.DoubleClickTime)
{
isDoubleClick = true;
}
}
}
void doubleClickTimer_Tick(object sender, EventArgs e)
{
milliseconds += 100;
doubleClickBar.Increment(100);
// The timer has reached the double click time limit.
if (milliseconds >= SystemInformation.DoubleClickTime)
{
doubleClickTimer.Stop();
if (isDoubleClick)
{
textBox1.AppendText("Perform double click action");
textBox1.AppendText(Environment.NewLine);
}
else
{
textBox1.AppendText("Perform single click action");
textBox1.AppendText(Environment.NewLine);
}
// Allow the MouseDown event handler to process clicks again.
isFirstClick = true;
isDoubleClick = false;
milliseconds = 0;
doubleClickBar.Value = 0;
}
}
// Paint the hit test and double click rectangles.
void Form1_Paint(object sender, PaintEventArgs e)
{
// Draw the border of the main hit test rectangle.
e.Graphics.DrawRectangle(Pens.Black, hitTestRectangle);
// Fill in the double click rectangle.
e.Graphics.FillRectangle(Brushes.Blue, doubleClickRectangle);
}
}
}
I've had similar problem with having events on double click and mouse up. I've experienced that the mouse up during the double click gets triggered twice during a double click as is reasonable.
What worked best for me was to hide the mouse up behind two levels on when it can be triggered. A bool and a timer with an interval short enough not to be noticeable by the user but longer than the interval between clicks in a double click.
The bool let's call it canMouseUp is true by default. and should be set to false during a double click to ignore the mouse up as the double click is finished.
the mouse up checks for canMouseUp and if it is false then it is set to true, nothing else. If canMouseUp is true then I start the mouseUpTimer.
double click stops the mouseUpTimer, sets canMouseUp to false and does it's own thing.
private void MyObject_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
try
{
if (!canMouseUp)
{
canMouseUp= true;
e.Handled = true;
}
else
{
mouseUpTimer.Start();
e.Handled = true;
}
}
catch (Exception)
{
throw;
}
}
private void MyObject_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
try
{
mouseUpTimer.Stop();
// Do what DoubleClick is supposed to do
canMouseUp = false;
e.Handled = true;
}
catch (Exception)
{
throw;
}
}
private void mouseUpTimer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
// Do what Mouse up is supposed to do.
}
catch (Exception)
{
}
}

Set backcolor to the button which user clicked

Hi all I am creating some button dynamically, and when user click on the button I need to set the BackColor for the selected button to some highlighted color, as per the code what I have written it is applying color for every button, instead of that I need to apply color for the user clicked button
My code for creating buttons is as follows
for(int i=0;i<5;i++)
{
Button btyDynamic = new Button();
btyDynamic .Click += new EventHandler(btyDynamic _Click);
btyDynamic .AutoSizeMode = AutoSizeMode.GrowAndShrink;
btyDynamic .AutoSize = true;
btyDynamic .Text = i.ToString();
btyDynamic .Tag = i.ToString();;
}
protected void btyDynamic(object sender, EventArgs e)
{
Button btn= sender as Button;
string strTag= btn.Tag.ToString();
switch(strTag)
{
case "0":
btn.BackColor=Color.LightSteelBlue;
break;
// Like this I am writing, now when in Case2 I need to remove the color of the first button and to show the backcolor of second button
}
}
You could store the last button selected and then reset the BackColor:
private Button _lastButtonSelected = null;
protected void btyDynamic(object sender, EventArgs e)
{
// Set new button back color
Button btn = sender as Button;
if(btn != null)
{
btn.BackColor = Color.LightSteelBlue;
}
// Reset last button color
if(_lastButtonSelected != null)
{
_lastButtonSelected.BackColor = ...; // Put default back color here
}
_lastButtonSelected = btn;
}
If you want the BackColor to remain LightSteelBlue if you click the same button twice, you just need to check that the _lastButtonSelected != btn as well.
you could make a foreach for all buttons, and remove background for all button not equal to sender. Suppose to save all buttons into an array (_AllButtons). you could write some code like this:
Button btn= sender as Button;
foreach(var currentButton in _AllButtons) {
if(currentButton !=btn) {
currentButton.BackColor=Color.Transparent;
}
}
A possible algorithm would be:
create the buttons once as you already do and bind the click event to one handler
in the click handler first reset all buttons to the standard background color
in the click handler find the currently clicked button using switch as you already do and set the color of this button
Sample code:
Action resetButtonColor = () =>
{
button1.BackColor = Colors.Red;
button2.BackColor = Colors.Red
button3.BackColor = Colors.Red;
};
resetButtonColor();
var selected = Colors.Green;
switch(strTag)
{
case "1": button1.BackColor = selected;
case "2": button2.BackColor = selected;
case "3": button3.BackColor = selected;
}
Then You must assign to the click event of this one button explicetely.
All others could have this handler, but the one button should not, because it is too generic handled in this way.
You can try this:
Color highLite = Color.Black;
public Form1()
{
InitializeComponent();
for (int i = 0; i < 20; i++)
{
Button b = new Button();
b.Text = i.ToString();
b.Tag = null;
b.Click += b_Click;
flowLayoutPanel1.Controls.Add(b);
}
}
void b_Click(object sender, EventArgs e)
{
Button b = sender as Button;
if (b == null)
return;
b.BackColor = highLite;
// clear backcolors
foreach (Control c in flowLayoutPanel1.Controls)
if (c != b)
c.BackColor = SystemColors.Control;
}
Make sure you are only setting backcolors of controls you want to set. Make the tag have something unique to tell you that you want to change it.
private Color offColor = Color.Red;
private Color onColor = Color.Blue;
private String btyPrefix = "bty";
private void btyDynamic_click(object sender, EventArgs e)
{
Control control = (Control)sender;
// enumerate this.Controls, but if they go into a different container, enumerate over that
this.Controls.OfType<Control>()
.Where(c => ((String)c.Tag).Contains(btyPrefix))
.ToList<Control>()
.ForEach(c =>
{
if (control == c)
c.BackColor = onColor;
else
c.BackColor = offColor;
}
);
}
private void Form1_Load(object sender, EventArgs e)
{
Button btyDontChange = new Button();
btyDontChange.AutoSize = true;
btyDontChange.AutoSizeMode = AutoSizeMode.GrowAndShrink;
btyDontChange.Text = "x";
btyDontChange.Tag = "something";
btyDontChange.Location = new Point(0, 0);
this.Controls.Add(btyDontChange);
for (int i = 0; i < 5; i++)
{
Button btyDynamic = new Button();
btyDynamic.Click += new EventHandler(btyDynamic_click);
btyDynamic.AutoSizeMode = AutoSizeMode.GrowAndShrink;
btyDynamic.AutoSize = true;
btyDynamic.Text = i.ToString();
btyDynamic.Tag = btyPrefix + i.ToString();
btyDynamic.Location = new Point((i+1) * 50, 0);
btyDynamic.BackColor = offColor;
this.Controls.Add(btyDynamic);
}
}

Address a generated button for clickevent

I have a class that creates panels with controls based on my database. It creates a panel with a button on each panel, per row in DB. How do I address one specific button to make a click event?
I'm a rookie, and maybe abit over my head, but you don't learn to swim in shallow water ;)
Any help appreciated!
while (myDataReader.Read())
{
i++;
Oppdrag p1 = new Oppdrag();
p1.Location = new Point (0, (i++) * 65);
oppdragPanel.Controls.Add(p1);
p1.makePanel();
}
class Oppdrag : Panel
{
Button infoBtn = new Button();
public void makePanel()
{
this.BackColor = Color.White;
this.Height = 60;
this.Dock = DockStyle.Top;
this.Location = new Point(0, (iTeller) * 45);
infoBtn.Location = new Point(860, 27);
infoBtn.Name = "infoBtn";
infoBtn.Size = new Size(139, 23);
infoBtn.TabIndex = 18;
infoBtn.Text = "Edit";
infoBtn.UseVisualStyleBackColor = true;
}
}
You'll need a method that matches the event thrown by clicking on the button.
i.e.)
void Button_Click(object sender, EventArgs e)
{
// Do whatever on the event
}
Then you'll need to assign the click event to the method.
p1.infoBtn.Click += new System.EventHandler(Button_Click);
Hope this helps.
You can add the event handler for the button when you create the button. You can even add a unique CommandArgument per button so you can distinguish one button from another.
public void makePanel()
{
/* ... */
infoBtn.UseVisualStyleBackColor = true;
infoBtn.Click += new EventHandler(ButtonClick);
infoBtn.CommandArgument = "xxxxxxx"; // optional
}
public void ButtonClick(object sender, EventArgs e)
{
Button button = (Button)sender;
string argument = button.CommandArgument; // optional
}

Get return value from pressed button

I have a form that pops up at a specific event. It draws up buttons from an array and sets the Tag value to a specific value. So if you are to press or click this button the function should return the Tag value.
How can I do this? And how do I know which button was clicked?
At this moment the code returns DialogResult, but I want to return the Tag value from the function. How shall I modify my code so that it can do this?
public static DialogResult SelectBox(string title, string[] btnArray, string[] btnValueArray)
{
Form form = new Form();
Button[] buttonArray;
buttonArray = new Button[5];
form.Text = title;
for (int i = 0; i < btnArray.Length; i++)
{
buttonArray[i] = new Button();
buttonArray[i].Text = btnArray[i];
buttonArray[i].Tag = new int();
buttonArray[i].Tag = btnValueArray[i];
buttonArray[i].TabStop = false;
buttonArray[i].Location = new System.Drawing.Point(0, i * 40);
buttonArray[i].Size = new System.Drawing.Size(240, 40);
}
form.ClientSize = new Size(240, 268);
form.Controls.AddRange(new Control[] { buttonArray[0], buttonArray[1], buttonArray[2] });
form.FormBorderStyle = FormBorderStyle.FixedDialog;
form.StartPosition = FormStartPosition.CenterScreen;
form.MinimizeBox = false;
form.MaximizeBox = false;
DialogResult dialogResult = form.ShowDialog();
return dialogResult;
}
Add a private variable in the form:
private object SelectedTag;
Add a button click handler:
private void Button_Click(object sender, EventArgs e) {
SelectedTag = ((Button)sender).Tag;
}
Assign the handler to each button you create:
..
buttonArray[i].OnClick += form.Button_Click;
..
Then in your static function, simply return form.SelectedTag instead of the dialogresult.
You could call the same click event for all buttons. then in your handler:
private void ButtonClick(object sender, EventArgs args)
{
Button oButton = (Button) sender;
object data = oButton.Tag;
}
The DialogResult property already tells you which button was clicked. You can set each individual button to return a different DialogResult, and then check for that at the bottom of the function.
And if you want to return the clicked button's Tag property instead, you need to change the function's return value to Object (because the Tag property is of type Object).
You can add a ButtonClick event handler in a TestForm, set the button's tag to the Form's tag.
Here is the sample.
Main Form:
private void Form1_Load(object sender, EventArgs e)
{
Object tag;
SelectBox("test", new String[] { "One", "Two", "Three" }, new String[] {"one value", "Two value", "three value" }, out tag);
MessageBox.Show(tag.ToString());
}
public static DialogResult SelectBox(string title, string[] btnArray, string[] btnValueArray, out Object tagValue)
{
TestForm form = new TestForm();
Button[] buttonArray;
buttonArray = new Button[5];
form.Text = title;
for (int i = 0; i < btnArray.Length; i++)
{
buttonArray[i] = new Button();
buttonArray[i].Text = btnArray[i];
buttonArray[i].Tag = new int();
buttonArray[i].Tag = btnValueArray[i];
buttonArray[i].TabStop = false;
buttonArray[i].Location = new System.Drawing.Point(0, i * 40);
buttonArray[i].Size = new System.Drawing.Size(240, 40);
// subscribe to button click event..
// the handler is in TestForm
buttonArray[i].Click += form.HandleOnButtonClick;
}
form.ClientSize = new Size(240, 268);
form.Controls.AddRange(new Control[] { buttonArray[0], buttonArray[1], buttonArray[2] });
form.FormBorderStyle = FormBorderStyle.FixedDialog;
form.StartPosition = FormStartPosition.CenterScreen;
form.MinimizeBox = false;
form.MaximizeBox = false;
DialogResult dialogResult = form.ShowDialog();
// set the out args value
tagValue = form.Tag;
return dialogResult;
}
TestForm that whose instance we create in the SelectBox dialog:
public partial class TestForm : Form
{
public TestForm()
{
InitializeComponent();
}
public void HandleOnButtonClick(Object sender, EventArgs e)
{
Button button = sender as Button;
if (button != null)
this.Tag = button.Tag;
}
}
Edit:
If you want to capture every button's value then expose a Dictionary<String, Object> Tags property.

Categories