binding custom control to an external button - c#

I have a custom control that i'm using in an external application. I want to bind a click event of a random button in the application to add data to my control.
Is something like that even possible?? Basically what i was thinking was creating a property in my control that allows a developer to add a button control to it at design time. And then when the application is run, any clicks registered on the button will be forwarded to a method in the custom control to add data.
Is this doable? if so, can someone explain what needs to be done exactly?

You can create a property of type Button in your custom control. Then when you put an instance of custom control on the designer, for that property, you will see a dropdown that shows all Button instances on the form which you can select one of them. It's enough to add a method to click event of the button in setter of the property:
using System;
using System.Windows.Forms;
public class MyControl : UserControl
{
private Button addButton;
public Button AddButton
{
get { return addButton; }
set
{
if (addButton != null)
addButton.Click -= new EventHandler(addButton_Click);
addButton = value;
if (addButton != null)
addButton.Click += new EventHandler(addButton_Click);
}
}
void addButton_Click(object sender, EventArgs e)
{
MessageBox.Show("Add Button Clicked!");
}
}
When you put it on designer, for AddButton property, a list o available buttons on the form will be shown. it's enough to choose one of them, then the behavior which you want (here in the example, showing the message box) will attach to click event of that button.

Related

c# label text won't update on usercontrol after button click

I have a usercontrol that is loaded to a panel on Form1 in a winform application when a menu option is selected. The usercontrol has buttons that are used to fire the printer select dialog and allow the user to setup multiple printers for the application. Each button configures the settings property in the application to store a printer. Under each button there is a label that displays the name of the printer from the settings property.
I am using events to manage the button clicks from the usercontrol. Everything works great with the events storing the correct printer in the settings property. However, I want the label to display the selected printer immediately after I select it in the printer dialog. It won't display the change of printer until I navigate away from the usercontrol and back. Then it shows the correct printer name for each button.
I am able to write to the label text just fine. I've tried refreshing the label, invalidating and updating the label. Nothing seems to work. Only navigating away and back will display the printer names in the labels.
Here is one of my button click handlers on Form1:
private void btnTwoByHalf_Click(object sender, EventArgs e)
{
ucPrinterSetup prn = new ucPrinterSetup();
twoByHalf.PropName = "TwoByHalfPrn";
twoByHalf.SetPrinter(twoByHalf.PropName);
prn.lblTwoByHalf.Text = twoByHalf.Printer;
}
Here is my menu option click handler:
private void configurePrintersToolStripMenuItem_Click(object sender, EventArgs e)
{
ClearFrames();
ucPrinterSetup printerSetup = new ucPrinterSetup();
pnlMenu.Controls.Add(printerSetup);
printerSetup.btnTwoByHalfClick += new EventHandler(btnTwoByHalf_Click);
printerSetup.btnFourByOneClick += new EventHandler(btnFourByOne_Click);
printerSetup.btnFourByTwoFiveClick += new EventHandler(btnFourByTwoFive_Click);
printerSetup.btnMiscClick += new EventHandler(btnMisc_Click);
printerSetup.btnDefaultClick += new EventHandler(btnDefault_Click);
printerSetup.btnSecondaryClick += new EventHandler(btnSecondary_Click);
ucConfigurePrinters configurePrinters = new ucConfigurePrinters();
pnlFrame.Controls.Add(configurePrinters);
}
Here is my button click handler from ucPrinterSetup.cs:
private void btnTwoByHalf_Click(object sender, EventArgs e)
{
if (btnTwoByHalfClick != null)
btnTwoByHalfClick(sender, e);
}
Everything else works fine. It just doesn't update the label.text after I select the new printer until I navigate away from ucPrinterSetup and back.
Update 1:
My printers are being stored in the application settings through:
twoByHalf.PropName = "TwoByHalfPrn";
twoByHalf.SetPrinter(twoByHalf.PropName);
twoByHalf.PropName is the name that I've pre-entered in the settings property for the application.
I then set the label text to the name of the printer with:
prn.lblTwoByHalf.Text = twoByHalf.Printer;
In Application-Settings I have preset printer names as:
TwoByHalfPrn - string - User - (no value)
The main problem seems to be that you set the label on a control other than the one you are showing.
When your click event (btnTwoByHalf_Click) is called, you should use
the user control that is currently showing, but instead you create a new one with ucPrinterSetup prn = new ucPrinterSetup();
This is not the same control that is showing, but a completely new control, so when you change the label in prn you change the label in an invisible control, the original control remains unchanged.
I can see 4 ways of getting the original control:
1.
You can get it from the menu. If you only have one instance of this control type in you menu, you can use something like (no error handling in my code):
ucPrinterSetup prn = pnlMenu.Controls.OfType<ucPrinterSetup>().First();
twoByHalf.PropName = "TwoByHalfPrn";
twoByHalf.SetPrinter(twoByHalf.PropName);
prn.lblTwoByHalf.Text = twoByHalf.Printer;
Or, if you do have more than one you can assign different names to your controls and use something like pnlMenu.Controls.Find("YourControlNameGoesHere", false).First();
2.
You can get it from the sender property in your event. The sender is the button in the control, so assuming the button is sitting directly in the control, the button's parent will be the control:
ucPrinterSetup prn = (ucPrinterSetup)((Control)sender).Parent);
If the button is not sitting directly in the control (for example, it might sit in a panel that sits in a control) then you might need to up the chain more, you can put a breakpoint in the event entry and inspect the sender.
3.
The third way is maybe the best, but it requires you to change your design. It seems that you create the control again and again each time the menu is clicked. Maybe there's a good reason for it, but assuming there's no real reason for it, it's probably better to create the user control once when you start, and just switch the original control in and out. Then you can just put your control in a class variable and use it from your event.
4.
And for completeness you can also use a lambda/anonymous method for your event and capture the control when you register the event.
If you do that, then in the method which you register the event, replace the registration code to something like this:
printerSetup.btnTwoByHalfClick += (sender, e) => btnTwoByHalf_Click(printerSetup );
And then change your event method signature and code to be like this:
private void btnTwoByHalf_Click(ucPrinterSetup prn)
{
twoByHalf.PropName = "TwoByHalfPrn";
twoByHalf.SetPrinter(twoByHalf.PropName);
prn.lblTwoByHalf.Text = twoByHalf.Printer;
}
This might be the easiest code and less error prone to use, though notice that if you need to unregister the event later on, it might prove tricky.

Call a method in another class from a control within a control?

I have a custom control created, comprised of a bunch of text boxes, 1 button and radio buttons.
I then have a "parent" control which only has this 1 custom control placed on it, and in the code behind I have a reference to this control's Presenter.
The presenter handles the actual code for searching (when the one button is pressed). How do I set up the button click event on the child control to call the Search method from the presenter?
So I have the following:
CtlSearchDetails
ViewSearchScreen
PresenterSearchScreen
The button click event is on CtlSearchDetails and it needs to call the method on PresenterSearchScreen. I cannot figure out how to reveal this method to the instace of the control on ViewSearchScreen.
In your custom child control, you want to expose an event for the button click:
public event Action OnButtonClicked;
Then hook the button clicked event from the designer
private void btn_myButton_Clicked(object sender, EventArgs e)
{
if (OnButtonClicked != null)
OnButtonClicked();
}
Then in your parent container, you want to handle this event from the child control
this.myChildControl.OnButtonClicked += new Action(onChildButtonClicked);
private void onChildButtonClicked()
{
// Do your search here
}

how to access a user define controls iner controls in parent form

I'm new to windows forms programming so my question may sound little strange.
I have created a user define control (countdown timer) now I'm creating n no of it dynamically in a form by Click of a button (Add new timer) its working well and good.
Here is the Creation Code
private void Addnew_Click(object sender, EventArgs e)
{
UserControl1.userControl11 = new UserControl1();
flowLayoutPanel1.Controls.Add(userControl11);
}
My user control has a Reset button that reset all the content inside the user define control.
it is also working, but What I want Allow user to reset all the Created timers using the “Reset All” button on the form.
Okay one way to do this.
Create a List<UserControl1> private member on your form called say _myUserControls
In your Addnew Handler add it to the list.
If you have a remove button, don't forget to remove from _myUserControls as well.
Add a Reset method to your UserControl1, that does what it needs to do.
Then in your Reset all button click handler
foreach(UserControl1 ctrl in _myUserControls)
{
ctrl.Reset();
}
Jobs a good 'un
The answer I referred you to in comments, would be a way of finding all instances of your UserControl1 class, so you wouldn't need an internal list.

Databound control won't lose focus [duplicate]

I have a Windows Forms Application. I have several forms in this application (a main form, and several specialized forms), and on only one form, click events are not firing for any of my buttons.
It is not that the code in the handler is broken. This can be determined by the fact that a breakpoint on the first line of the handler is never reached when clicking the button.
Other events are working (I'm using CheckedChanged events on this form and they are behaving).
My team members have reviewed, and also can't spot the problem.
Here is a simplified view of my code:
Designer Generated Code
partial class MyForm
{
private System.Windows.Forms.Button addButton;
private void InitalizeComponent()
{
this.addButton = new System.Windows.Forms.Button();
this.addButton.Name = "addButton";
// Drawing statements here
this.addButton.Click += new System.EventHandler(this.addButton_Click);
this.Controls.Add(this.addButton);
}
}
My Code
public partial class MyForm : Form
{
public MyForm()
{
InitializeComponent();
}
private void addButton_Click(object sender, EventArgs e)
{
MessageBox.Show("The debugger is not reaching a break point on this line");
}
}
Edit: Additional Information from Testing
There are several data-bound dropdownlists in my form. I have discovered that the click event only fails to fire if I make a selection in a drop down box first.
If I make no selections, the break point in the button's handler fires. Otherwise it doesn't. There are no events registered on these drop down lists.
Here is the reason:
When using data binding, when you enter a value in a data bound control, it first tries to validate entry and then if the entry was valid, data binding will put the value in data source, but if a validation error occurs validation returns false and your control goes to invalid mode.
When a child control of form didn't validate, by default you can not change focus from invalid control.
Click on a button by default causes validation of the control that are losing the focus, so you can't click on button, as you see your button reflect to mouse but not actually click.
The same problem will happen if you handle Validating event of a control like TextBox and set e.cancel = true.
Here is the fix:
you can fix this behavior using either of following options:
Set CausesValidation property of your button to false
Set AutoValidate property of your form to AutoValidate.EnableAllowFocusChange
This will do the trick for you
Change
public ScheduleMeeting()
{
InitializeComponent();
}
to
public MyForm()
{
InitializeComponent();
}
I have discovered the issue after further testing.
I the issue is not with button events, but with the form becoming blocked after making a selection from a drop down box.
I have not yet discovered why the form blocks after the drop down is selected (it has no events, but does have databinding, so there are some possible causes there).
Thank you for all your help!

.NET UserControl accept button best practice?

I have a windows forms app where I have split different functionality into several user controls. I want each of these user controls to have an accept button.
Any best practices here?
My idèa is to detect which user control that has focus, and than set it in the parent Form.
Any other idèas?
The best practice is usually to only have one accept button for your form so that its behavior is consistent. It generally would be confusing for users if hitting return caused different actions depending on which section of the form had focus. However, if you have a specialized application or users have requested this feature then I think the solution you propose would work.
Jan Miksovsky has an excellent blog on UI design, and wrote an article about this very thing.
Most UI platforms allow a designer to
indicate which button in a dialog
should be the default button: the
button that will be pressed if the
user types the Enter key. The default
button is generally the button the
user is most likely to press next,
often a button like OK that closes the
dialog. In very high-traffic dialogs,
you may want to consider dynamically
changing the default button to save
keystrokes and help speed the user's
task.
The example he uses is the "Select Names" dialog in Microsoft Outlook, which changes the default button depending on what you are doing.
I assume each user button is its own instance on the individual user controls?
If so then you can trap the button events on the Parent form. If you expose the individual buttons through a property you can tie into their Click events. Like all controls they have a name property so you can have one method that is called on all button click events.
Below I have a partial sample code. I have two user controls that have one button each. The button on UC1 is named "btn1" and "btn2" for UC2. I call the exposed property "ButtonOK"
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
public Button ButtonOK
{
get { return btn1; }
}
}
public partial class UserControl2 : UserControl
{
public UserControl2()
{
InitializeComponent();
}
public Button ButtonOK
{
get { return btn2; }
}
}
Now on the parent ("Form1") when it loads have a mthod that ties into the Click events of each button but it calls the same method. Inside the method I test for the "Name" property.
public Form1()
{
InitializeComponent();
}
void Form1_Load(object sender, EventArgs e)
{
RegisterButtonEvents();
}
void RegisterButtonEvents()
{
userControl11.ButtonOK.Click += new EventHandler(ButtonOK_Click);
userControl21.ButtonOK.Click += new EventHandler(ButtonOK_Click);
}
void ButtonOK_Click(object sender, EventArgs e)
{
Button btn = sender as Button;
if (btn != null)
{
if (btn.Name == "btn1")
{
Console.WriteLine(" ButtonOK from UserControl1 was pushed. The tag is " + btn.Tag.ToString());
}
else if (btn.Name == "btn2")
{
Console.WriteLine(" ButtonOK from UserControl2 was pushed. The tag is " + btn.Tag.ToString());
}
}
}
You can also user the "Tag" property of a control. This property can be very useful as it can reference objects.
You don't need to do exactly as shown but you can use any "Parent" form to get a reference to the UserControls, have them expose their Buttons, then you can do anything you want with properties and events from those Buttons (or any control for that matter).
Keep in mind that if you are tying into the click event on the user control also (in addition to the parent form), you will have to be mindful of the order in which it will enumerate through it list of delegates and execute code after the event is intiated.
Hope that helps.
I know this is an old post, but I think I figured it out.
Use the "Enter" event on each user control from the main form, such that when the user "enters" (focuses on) the user control, this.AcceptButton = myUserControlButton. You can also use the "Leave" event on each user control to set the accept button back to the default, if you have one.
I'm not sure if I understood your question correctly.
If you want to assign one event to several buttons:
For this you could for instance:
- Get the button name on the Button_Click event.
- Enumerate between names
- Iterate over the controls.
Example bellow:
"How to get the button name from the Button_Click event".
// First; dont forget to assign the "Button_Click" event to your Button(s).
private void Button_Click(object sender, EventArgs e)
{
// The line bellow assigns to "btn" variable the currently clicked button.
Button btn = (Button)sender;
// Then using a switch block; you can compare the button name and
// perform the action desired for the clicked button.
switch(btn.Name)
{
case "buttonName1": /* Do Something Here */ break;
case "buttonName2": /* Do Something Here */ break;
// etc
}
}
Additionally; if you require; there's always the way to retrieve the Button outside the form class by exposing them.

Categories

Resources