Click event not firing for custom UserControl on a form - c#

I have created a UserControl called Toggle, this is my code for it
[DefaultEvent("Click")]
public partial class Toggle : UserControl {
public bool ToggleStatus { get { return toggleStatus; } }
private bool toggleStatus { get; set; }
public Toggle() {
InitializeComponent();
toggleStatus = true;
}
private void toggleClick(object sender, EventArgs e) {
if (toggleStatus) { // currently set as "true" or "on"
this.lblSwitch.Dock = DockStyle.Right;
this.pnlBackground.BackColor = System.Drawing.Color.Red;
toggleStatus = false;
} else { // currently set as "false" or "off"
this.lblSwitch.Dock = DockStyle.Left;
this.pnlBackground.BackColor = System.Drawing.Color.Green;
toggleStatus = true;
}
}
}
The toggleClick method is tied to the click event of controls within the UserControl; this fires off just fine.
However, when I put my Toggle control on a form and attempt to tie an event to the click of it, it won't fire off.
private void toggleSoundClick(object sender, EventArgs e) {
soundToggle = !soundToggle;
}
I've made sure that the proper method is tied to the click event in my Designer.cs file of both my UserControl and my form
UserControl:
this.lblSwitch.Click += new System.EventHandler(this.toggleClick);
this.pnlBackground.Click += new System.EventHandler(this.toggleClick);
(I have it tied to two controls on my Toggle since I want it to fire no matter where you click on the control)
Form:
this.tglSound.Click += new System.EventHandler(this.toggleSoundClick);
The expected behavior for the UserControl is to fire off toggleClick (which it does) then the form should fire off toggleSoundClick (which it doesn't). I have seen this behavior work fine for other UserControls I have designed and used in this same project.
To clarify:
I have a UserControl called ServerDisplay. I have a method tied to the click event of the background panel of ServerDisplay (in the code for ServerDisplay) that shows a random MessageBox:
private void ServerDisplay_Click(object sender, EventArgs e) {
MessageBox.Show("test");
}
Then, I have a ServerDisplay control contained within my form. I have a method tied to the click event of it as well (in the code for my form)
private void serverDisplayClick(object sender, EventArgs e) {
if (loaded) {
ServerDisplay display = (ServerDisplay)sender;
this.lblLastServer.Text = "Last server joined was " + display.Server.Name + " at " + DateTime.Now.ToString("h:mm tt");
centerControl(this.lblLastServer);
}
}
When I click on the ServerDisplay control in my form, it shows the MessageBox (code from within ServerDisplay), then updates the label I specified in the code (code from form). This is the intended behavior, but it is not working for my other UserControl.

I finally figured it out! The way I had the control set up, I had the control itself, a panel filling up the entire background (I used this for the color), and then another panel inside the first panel to act as the "switch".
When I got rid of the first panel and just used the background of the control for the color and a small panel for the switch, it works when I click the background, but not when I click the "switch" panel. I guess this opens up more questions that I'll have to ask separately from this one, but at least I got my answer.

Related

How to correctly highlight buttons on click?

So I have built an application in C# using Winforms and my application uses a few different buttons. I'd like to have a highlight on the button that has been clicked to show what 'tab' you're in.
I've tried doing the following;
// BUTTONS //
private void dashboard_btn_Click(object sender, EventArgs e)
{
// Load Form
OpenChildForm(new FormDashboard());
dashboard_btn.FlatAppearance.BorderColor = Color.Red;
dashboard_btn.FlatAppearance.BorderSize = 1;
}
However, this of course doesn't work nicely since it adds a border around the button but when I click another button the border also stays around the previous button.
How would you implement a feature to add a border around the button that get's clicked but have the border disappear after you click another button?
Thank you for any feedback!
EDIT:
I've implemented Jimi's advice and used the Leave event to change the border around the button back to 0. However I'm not sure how to implement this in a global way so all my buttons are subscribed to this event.
My code now looks like this;
// BUTTONS //
private void dashboard_btn_Click(object sender, EventArgs e)
{
// Load Form
OpenChildForm(new FormDashboard());
// Button Highlight
dashboard_btn.FlatAppearance.BorderColor = Color.Red;
dashboard_btn.FlatAppearance.BorderSize = 1;
}
// BUTTON REMOVE HIGHLIGHT //
private void dashboard_btn_Leave(object sender, EventArgs e)
{
dashboard_btn.FlatAppearance.BorderSize = 0;
}
EDIT 2:
I ended up using Jimi's example and this worked for me :)
This might lend itself to a RadioButton style functionality because clicking a different radio button in the same container will uncheck the others. So, to implement the "generalized approach" that you mention in your comment, you could make a simple custom RadioButtonEx class where the Appearance property is set to Button then change your border style when the Checked property changes. In this example, the Click event has been changed to static so that clicking on any button directs the event to the common onAnyClick method.
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
RadioButtonEx.Click += onAnyClick;
}
private void onAnyClick(object sender, EventArgs e)
{
label1.Text = ((RadioButtonEx)sender).Text;
}
}
public class RadioButtonEx : RadioButton
{
public static new event EventHandler Click;
public RadioButtonEx()
{
FlatAppearance.BorderColor = Color.Red;
FlatAppearance.BorderSize = 1;
Appearance = Appearance.Button;
}
protected override void OnCheckedChanged(EventArgs e)
{
base.OnCheckedChanged(e);
if(Checked)
{
FlatStyle = FlatStyle.Flat;
Click?.Invoke(this, EventArgs.Empty);
}
else
{
FlatStyle = FlatStyle.Standard;
}
}
}

TextBox took back focus while other controls don't

I wanted to focus to a TextBox when I leave an other TextBox.
Let's say I have 3 textboxes. The focus is in the first one, and when I click into the second one, I want to put the focus into the last one instead.
I subscribed to the first textbox's Leave event and tried to focus to the third textbox like: third.Focus(). It gains focus for a moment but then the second one got it eventually (the one I clicked).
Strangely if I replace the second TextBox to a MaskedTextBox (or to any other control), the focus remains on the third one.
Pressing Tab does work though.
These are plain textboxes right from the toolbox.
What is the reason, how can I solve this?
Try to handle Enter event of the textBox2. (In properties window double click on Enter event)
//From Form1.Designer.cs
this.textBox2.Enter += new System.EventHandler(this.textBox2_Enter);
private void textBox2_Enter(object sender, EventArgs e)
{
textBox3.Focus();
}
EDIT:
This code looks very strange, but it works for me. According to this post HERE I use ActiveControl property instead of Focus() method. But behavior of TextBox is very strange because it try to be focused multiple times.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
foreach (Control control in Controls)
{
control.LostFocus += (s, e) => Console.WriteLine(control.Name + " LostFocus");
control.GotFocus += (s, e) =>
{
Console.WriteLine(control.Name + " GotFocus");
if (!requestedFocusToTextBox2) return;
ActiveControl = textBox2; //textBox2.Focus() doesn't work
requestedFocusToTextBox2 = false;
};
}
}
private bool requestedFocusToTextBox2;
private void textBox1_Leave(object sender, EventArgs e)
{
ActiveControl = textBox2;
requestedFocusToTextBox2 = true;
}
}

Why does removing a control from its parent trigger VisibilityChanged with Visible = true?

I am working with some legacy code where I can not introduce big changes.
There is a control that has logic associated to the OnVisibleChanged event.
At one point during the Application Life-Cycle the control is removed from its parent, and when that happens the OnVisibileChanged event is fired two times. The first Time the control's visibility is false, and the second time is true.
Why is this happening? Why is the visibility changed being triggered the second time and with Visible being true?
A simple way to reproduce the behavior I describe:
Create a control:
class MyButton: Button
{
public MyButton()
{
Text = "Test";
}
protected override void OnVisibleChanged(EventArgs e)
{
base.OnVisibleChanged(e);
MessageBox.Show(string.Format("Im now visible {0}", Visible));
}
}
Use it in a form and remove it on the on click event of otherButton:
public partial class Form1 : Form
{
private MyButton myButton = new MyButton();
private GroupBox myGroupBox = new GroupBox();
private Button otherButton = new Button();
public Form1()
{
InitializeComponent();
otherButton.Text = "Remove";
otherButton.Click += otherButton_Click;
this.myGroupBox.Controls.Add(myButton);
this.Controls.Add(otherButton);
this.Controls.Add(myGroupBox);
}
void otherButton_Click(object sender, EventArgs e)
{
myGroupBox.Controls.Remove(myButton);
}
}
After running this, if you click the otherButton, the Message will be shown twice, first the Visibility will be false and the second time will be true.
The cause is rooted somewhere in the native call to:
[DllImport("user32.dll")]
public static extern IntPtr SetParent(HandleRef hWnd, HandleRef hWndParent);
which is called in the Control.Remove(...) method. If you replace Controls.Remove(myButton); with SetParent(myButton.Handle, IntPtr.Zero); the same two events will fire.
My guess is that it is convenient to have the VisibleChanged event fire when the control is removed from its parent. However, the control was never explicitly hidden though. So the second call has to set the Visible property back to true. Otherwise if the button is added back to the control, it won't be visible.

Winforms Control

I have a button which I use all the time as a little pick button next to a combobox. When I click the button I open a larger full list. This side of things work well and I do not have a problem with this..
My problem lies when someone said to me can you change that ugly icon you picked to my nice icon.
I went crap, I have hundreds of these buttons on many forms. So I thought I will create a custom control called PickButton (which is a standard button and heap of default proeprties set) and drop these on the form everywhere instead. In the code of the PickButton custom control I set some properties and the image to the customers nice icon.
So I drop the PickButton from my toolbox onto the form, so far things are looking pretty good and I am feeling a bit clever. Now I think to myself I will change back to my nice icon not the crappy one the customer picked and change the code in the PickButton custom control. But I cannot get rid of that customers icon, because the code when the PickButton run happens before the code in the designer file which has the customers icon.
So my aim was to have a PickButton control and be able to change the icon and other properties in one place and all the properties would be set when an instance of the control is created and displayed on the form.
Was I not so clever and went about achieving the task the wrong way???
This is my PickButton custom control class
public class PickButton : Button
{
public PickButton()
{
InitialiseButton();
}
internal void InitialiseButton()
{
this.ImageAlign = ContentAlignment.MiddleCenter;
this.Image = WindowsFormsApplication1.Properties.Resources.Cancel.ToBitmap();
this.Size = new Size( 28, 28 );
this.Dock = DockStyle.Fill;
this.Margin = new Padding( 0, 2, 2, 0 );
this.Text = string.Empty;
}
}
Now I drop one onto my form and the code in the designer is as follows
//
// pickButton1
//
this.pickButton1.Dock = System.Windows.Forms.DockStyle.Fill;
this.pickButton1.Image = ((System.Drawing.Image)(resources.GetObject("pickButton1.Image")));
this.pickButton1.Location = new System.Drawing.Point(0, 0);
this.pickButton1.Margin = new System.Windows.Forms.Padding(0, 2, 2, 0);
this.pickButton1.Name = "pickButton1";
this.pickButton1.Size = new System.Drawing.Size(284, 262);
this.pickButton1.TabIndex = 0;
this.pickButton1.Text = "pickButton1";
this.pickButton1.UseVisualStyleBackColor = true;
Now I want to change the image so I change my PickButton code to use a different icon
this.Image = WindowsFormsApplication1.Properties.Resources.Browse.ToBitmap();
Run the application andd the first icon is still the one being displayed because of this line of code in the designer file
this.pickButton1.Image = ((System.Drawing.Image)(resources.GetObject("pickButton1.Image")));
The concept of setting all the properties in one place was a good idea, it just wasn't implemented quite right. I would make this class inherit from UserControl instead of from Button. By making it a UserControl, you can use the designer to set all the properties you want, like the default Image for the button. Set that in the designer, then just drag and drop your UserControl from the toolbox onto your forms. If you are only using your "PickButton" control with comboboxes, I would put the combobox on the UserControl as well. If you ever want to change your button image in the future (or any other property for that matter), you will be able to change it in ctlPickButton and that will propogate the changes to all the instances used throughout your project(s).
ctlPickButton:
public partial class ctlPickButton : UserControl
{
public event EventHandler pickButtonClicked;
public ctlPickButton()
{
InitializeComponent();
}
//Allows buttons image to be set in code if necessary
public Image Image
{
get
{
return button1.Image;
}
set
{
if (Image != null)
{
button1.Image = value;
}
}
}
private void button1_Click(object sender, EventArgs e)
{
if (pickButtonClicked != null)
{
pickButtonClicked(sender, e);
}
}
}
Demo Form:
public Form1()
{
InitializeComponent();
ctlPickButton1.pickButtonClicked += new EventHandler(ctlPickButton1_pickButtonClicked);
ctlPickButton2.pickButtonClicked += new EventHandler(ctlPickButton2_pickButtonClicked);
}
void ctlPickButton2_pickButtonClicked(object sender, EventArgs e)
{
if (comboBox2.SelectedItem != null)
{
MessageBox.Show(comboBox2.SelectedItem.ToString());
}
}
void ctlPickButton1_pickButtonClicked(object sender, EventArgs e)
{
if (comboBox1.SelectedItem != null)
{
MessageBox.Show(comboBox1.SelectedItem.ToString());
}
}
private void Form1_Load(object sender, EventArgs e)
{
comboBox1.Items.Add("French");
comboBox1.Items.Add("Spanish");
comboBox1.Items.Add("English");
comboBox1.Items.Add("German");
comboBox2.Items.Add("Pizza");
comboBox2.Items.Add("Hamburger");
comboBox2.Items.Add("Potato");
comboBox2.Items.Add("Chicken");
//Shows how the default image set in the designer can be overwritten for a
//specific instance using the "Image" property
ctlPickButton2.Image = Testbed.Properties.Resources.searchIcon2;
}
}
Image of ctlPickButton in designer
I think I've found a simple, clean solution:
In the CustomButton class (which inherits from System.Windows.Forms.Button), override the Refresh() method, and set the image of the button to the one you want to see:
public class CustomButton : Button
{
public override void Refresh()
{
Image = MyResources.HappyFace;
}
}
In the form that will hold an instance of your CustomButton, simply call customButton.Refresh() in the constructor, after InitializeComponent():
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
customButton.Refresh();
}
}
I've put a demo application up on Github.

Hiding datagridviews bug

I have a windows form with a panel on the left, which consists purely of radiobuttons, and a tabcontrol in the middle, with multiple tab pages within it. Each of these individual tabpages have a series of datagridviews within it, which are shown and hidden depending on which radio button you check.
I accomplish this effect by having each of the radiobuttons on the left assigned a CheckChanged event, which loops through all of the controls within the tabpagecontrol.SelectedTab, and calls .Show() on the corresponding datagridview and calls .Hide() on the rest so that only one datagridview is visible at one time.
My problem occurs when i try to programmatically check one of these RadioButtons. Lets say in Method X, I write RadioButtonA.checked = true. This triggers the usual CheckedChange event handling, which loops through all the datagridviews on the currently selected tabpage and calls .Hide() on everything except the one datagridview form that the radiobutton is supposed to bring up and calls .Show() instead. However, on one of these .Hide() calls on the datagridview, it ends up triggering the RadioButtonA.CheckedChange event AGAIN for a second time. When i look at the sender argument passed to the function, it shows that the sender is the RadioButton i just programmatically clicked on.
I am adding these datagridviews programmatically and can confirm that there are no eventhandlers assigned whatsoever to them. Can anyone help me determine what is causing this additional event to get triggered? Thanks.
For obnoxious change events that trickle through and upset other event handlers on my forms, I've found the only solution is to add a small boolean value:
bool radioIng;
void MyMethod() {
radioIng = true;
try {
radioButton1.Checked = true;
// etc.
} finally {
radioIng = false;
}
}
void radioButton_EventHandler(object sender, EventArgs e) {
if (radioIng) return;
// rest of code here
}
EDIT:
Alternately, you could just remove all of your event handlers and reconnect them later:
void MyMethod() {
try {
radioButton1.CheckChanged -= radioButton_EventHandler;
radioButton2.CheckChanged -= radioButton_EventHandler;
radioButton3.CheckChanged -= radioButton_EventHandler;
// execute your code
radioButton1.Checked = true;
} finally {
radioButton1.CheckedChanged += new EventHandler(radioButton_EventHandler);
radioButton2.CheckedChanged += new EventHandler(radioButton_EventHandler);
radioButton3.CheckedChanged += new EventHandler(radioButton_EventHandler);
}
}
void radioButton_EventHandler(object sender, EventArgs e) {
if (sender == radioButton1) {
// code here to handle
} else if (sender == radioButton2) {
// code here to handle
} else if (sender == radioButton3) {
// code here to handle
}
}

Categories

Resources