Dynamically set method for tabPage - c#

I have TabControl. I added it to tabpages. To one of them(tpTags) I dynamically add usercontrol tagsModule. When I'll click at tpTags I wanna to call method on tagsModule BindData
NEW CODE:
TabPage tpTags = new TabPage();
tabControl1.TabPages.Add(tpTags);
...setting properties...
TagsModule tagsModule = newTagsModule(_countryCode, ObjectType.Country);
tpTags.Select() = tpTags.BindData(); //**How do it ??**
tpTags.Controls.Add(tagsModule);
It could be: "how do I set an event that triggers when this tab is selected?"

You have to wire up the delegate to the event like this:
tabControl1.SelectedIndexChanged += new EventHandler(this.tabControl1_SelectedIndexChanged);
Now you can put all your code inside this method
private void tabControl1_SelectedIndexChanged(object sender, System.EventArgs e)
{
if(TabControl1.SelectedTab == tpTags)
{
// BindData();
}
}
BindData() runs whenever your tabPage 'tpTags' is selected. If you want only for the first time, set a flag.

If you mean "how do I make this the current tab", then:
tabs.SelectedTab = tpTags;
If you mean "how do I respond when this tab is selected", then look at the tpTags.SelectedIndexChanged event (you don't necessarily need to care about the index when handling this event - you can just check tabs.SelectedTab again).

Related

User Control Form Click event not clicking on label C#

I have a problem with User form Click that I am trying to make in C# using a usercontrol.
It consists of a picturebox and a label. I want to call the click event but the picturebox and the label don't do anything when I click them. Only the background area of the usercontrol does what I want it to do. Any ideas?
here's my code
for (int i = 0; i < listitems2.Length; i++)
{
listitems2[i] = new declined();
//adding sample data to each dynamic user
listitems2[i].dicon = dicon[i];
listitems2[i].did = did[i];
listitems2[i].dname = dname[i];
//adding data to flow layout panel
flowLayoutPanel2.Controls.Add(listitems2[i]);
// below line will assing this (usercontrolclick) event to every user control created dynamically
listitems2[i].Click += new System.EventHandler(this.UserControl_Click);
}
for click function
void UserControl_Click(object sender, EventArgs e)
{
string ctrlName = ((UserControl)sender).Name;
applicable obj = (applicable)sender;
studid.Text = obj.id;
studname.Text = obj.name;
pictureBox1.Image = obj.icon;
}
You added OnClick handler to your UserControl, so only clicks made on UserControl will be registered. To enable Click event for all the controls on your form, you need to add your click handler to all other controls.
But, according to your code, you're adding click handling on form where your control is located. In this case, you cannot register clicks on control from "outside" (you can by making Label and PictureBox controls public and adding handlers for their OnClick events but that is wrong way to do it)
My suggestion is to make custom event on your form and raise it on Form, Label and PictureBox click, and then make handler for that event on form which holds your UserControl.
Something like this:
//make custom eventHandler on your UserControl
[Browsable(true)]
public event EventHandler UserControlClicked;
//constructor
public UserControl1()
{
InitializeComponent();
//after intialize compoment add same handler for all three controls
this.Click += ControlClicked;
this.pictureBox1.Click += ControlClicked;
this.label1.Click += ControlClicked;
}
//this method will "catch" all clicks
private void ControlClicked(object sender, EventArgs e)
{
//raise event
UserControlClicked?.Invoke(this, e);
}
and on form where your custom control is, add handler for UserControlClicked (maybe with cast, I don't know what listItems2[i] contains):
listitems2[i].UserControlClicked+= new System.EventHandler(this.UserControl_Click);
or maybe like this (with casting)
(listitems2[i] as UserControl1).UserControlClicked+= new System.EventHandler(this.UserControl_Click);
and handle the rest in your UserControl_Click method like before

WinForms SelectedIndexChangeCommitted not firing

I'm populating a combobox from a datasource and I have code for when the user changes the selection in the combobox. So obviously I don't want the code in the SelectedIndexChanged method to fire on form load.
This SO question was answered by suggesting two things:
1) Before and after loading the data to the combobox use this code:
private void LoadYourComboBox()
{
this.comboBox1.SelectedIndexChanged -= new EventHandler(comboBox1_SelectedIndexChanged);
// Set your bindings here . . .
this.comboBox1.SelectedIndexChanged += new EventHandler(comboBox1_SelectedIndexChanged);
}
I tried that with this code:
this.cboSelectCategory.SelectedIndexChanged -= new EventHandler(cboSelectCategory_SelectedIndexChanged);
However, the cboSelectCategory_SelectedIndexChanged part has a red error squiggly and hovering over it says: The name cboSelectCategory_SelectedIndexChanged does not exist in the current context. I tried that code in both the form_load and the method that actually populates the combobox.
2) That same SO question had the answer to use the event SelectedIndexChangeCommitted.
private void cboSelectCompany_SelectedIndexChangeCommitted(object sender, EventArgs e)
{
string selectedCat = cboSelectCategory.SelectedValue.ToString();
Console.WriteLine(selectedCat);
}
But that event isn't firing when I change the selection in the combobox.
Am I missing something somewhere? Is my code off or in the wrong place?
So obviously I don't want the code in the SelectedIndexChanged method to fire on form load.
If you bind your combobox in the form's constructor (after InitializeComponent()) then SelectedIndexChanged will fire before the form is visible, so you can simply return from the selectedindexchanged event if the form is invisible:
public MainForm()
{
InitializeComponent();
DataTable dt = new DataTable();
dt.Columns.Add("Name");
dt.Columns.Add("Code");
dt.Rows.Add("Milk", "MLK");
dt.Rows.Add("Bread", "BRD_WHITE");
dt.Rows.Add("Bread", "BRD_BROWN");
dt.Rows.Add("Coffee", "COFF");
comboBox1.DataSource = dt;
comboBox1.DisplayMember = "Name";
comboBox1.ValueMember = "Code";
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (!this.Visible)
return;
MessageBox.Show("a");
}
It's often easier to simply return from an event handler at an unwanted time than to mess around trying to remove and add event handlers
Side note: If you use a strongly typed dataset and create the bindings using the windows forms designer, the event doesn't fire, I believe because the forms designer InitializeComponent() calls Begin/EndInit on the components at the start and end

Adding events to Form designer file

I created a new Event in my user control (SearchControl) like this:
//Event which is triggered on double click or Enter
public event EditRecordEventHandler EditRecord;
public delegate void EditRecordEventHandler(object sender, EventArgs e);
//Supressing the events
private bool _raiseEvents = true;
private void OnEditRecord(System.EventArgs e)
{
if (_raiseEvents)
{
if (this.SearchResultGridView.FocusedRowHandle > -1)
{
if (EditRecord != null)
{
EditRecord(this, e);
}
}
}
}
Now this Event is called when user double click a row in a grid. So from the properties window I selected the MouseDoubleClick Event of the grid view and called the above created EditRecord event.
private void SearchResultListGridControl_MouseDoubleClick(object sender, MouseEventArgs e)
{
// Check whether the user clicked on a real and not a header row or group row
DevExpress.XtraGrid.Views.Grid.ViewInfo.GridHitInfo info = SearchResultGridView.CalcHitInfo(e.Location);
if (info.InRow && !SearchResultGridView.IsGroupRow(info.RowHandle))
{
OnEditRecord(e);
}
}
Now the issue I am facing is every time I double click a row in grid view it calls the SearchResultListGridControl_MouseDoubleClick() which then calls OnEditRecord(), however the value of EditRecord is everytime null.
To solve this I checked the designer file of the Main Control which has SearchControl and could not find the EditRecord Event entry in this. So I manually created it like this:
this.MySearchControl.EditRecord += new performis.BA.Merkmalsleisten.Search.SearchControl.EditRecordEventHandle(this.MySearchControl_EditRecord);
Now the things are working fine, but my question is why it did not create it automatically at the first place? And as far I know it is not recommendable to add anything manually to the designer file..is there any other way I can do it?
Thanks
When you create event it has to be used in the form designer similar to how you are using MouseDoubleClick for the Grid (so you need to find event in the Misc category, because you didn't define CategoryAttribute, double clicked there, etc).
If I understand it right you want to subscribe to event automatically, when form is created. You can do this in the control constructor (find parent form control.Parent or control.FindForm()) or perhaps in the special method, which you have to call from the form constructor, which in turn is basically similar to wiring event manually (which you did in the designer created file, but, instead, you can do in the form file, which is totally ok to edit) Up to you.
Sure.
A better practice would be to add your binding line:
this.MySearchControl.EditRecord += new performis.BA.Merkmalsleisten.Search.SearchControl.EditRecordEventHandle(this.MySearchControl_EditRecord);
To the form's constructor. something like:
public MyForm()
{
this.MySearchControl.EditRecord += new performis.BA.Merkmalsleisten.Search.SearchControl.EditRecordEventHandle(this.MySearchControl_EditRecord);
//The rest of your constructor.
}

How do I make buttons do the same thing?

I just started programming, and I want to use WinForms to make multiple buttons that you can click on to change from white to lime-green and back to white. I have done this for one button:
private void button1_Click(object sender, EventArgs e)
{
if (button1.BackColor != Color.Lime)
{
button1.BackColor = Color.Lime;
}
else
{
button1.BackColor = Color.White;
}
}
Now I could copy and paste that for all of the buttons, but I know that is inefficient; and if I use winforms to reference button1 on button2, it will just change the color of button1 (obviously).
So, do I need to use a helper method, new class, or something else? What would that look like?
There are a couple of approaches. One might be to create a common function which the different buttons call:
private void button1_Click(object sender, EventArgs e)
{
ChangeColor(button1);
}
private void ChangeColor(Button button)
{
if (button.BackColor != Color.Lime)
button.BackColor = Color.Lime;
else
button.BackColor = Color.White;
}
Then each button handler can use that same function call.
Or, if all of these buttons will always ever do exactly the same thing, then you can use one click handler function for all of them. In this case what you'd need to do is determine which button invoked the handler (whereas you're currently referencing button1 directly) so that you know which one to change. The sender object passed into the handler function is actually a reference to the form element which invoked the handler. All you need to do is cast it:
private void button_Click(object sender, EventArgs e)
{
var button = (Button)sender;
if (button.BackColor != Color.Lime)
button.BackColor = Color.Lime;
else
button.BackColor = Color.White;
}
So first the handler grabs a reference to the button which invoked it, then runs the logic on that button. Note also how I made the name of the handler function slightly more generic. Now you'd go to the form designer and set button_Click as the click handler for all of the buttons which should invoke this.
You do this the exact same way you'd do it for any C# class. You derive your own class and customize the base class behavior. Every event has a corresponding OnXxxx() method that you can override.
Add a new class to your project and paste this code:
using System;
using System.Windows.Forms;
class MyButton : Button {
protected override void OnClick(EventArgs e) {
// Your code here
//...
base.OnClick(e);
}
}
Change the code in OnClick() to do what you want to do. Compile. You'll now have your own button control on the top of the toolbox. And can drop as many copies of it as you want on a form. They'll all behave the same without having to add any code in the form.
Probably the easiest way would be to have each button invoke the same click handler. Then inside of your handler use the Sender instead of hard coding Button1.
private void buttons_Click(object sender, EventArgs e)
{
var theButton = (Button) sender;
if (theButton.BackColor != Color.Lime)
{
theButton.BackColor = Color.Lime;
}
else
{
theButton.BackColor = Color.White;
}
}
You can get the button that raised the Click event by casting sender to Button.
You can then add the same handler to every button.
I'm a VB guy.... in VB.Net you can add multiple handlers for events and connect multiple events to the same handler.
This sub hooks all clicks to color the buttons.
Private Sub ColorButtons(sender As System.Object, e As System.EventArgs) _
Handles Button1.Click, Button2.Click, ..
I do this all the time accidentally because I drag/copy a control to make a new one and the new button gets added to the original's events.
Other Subs can handle the same events to do other work - both will execute.
No idea how to do this in C#.
The proper way to do this really is to associate each button's click event to the function you have coded for that purpose (you want the function to run when the button is clicked, right?), so add the following (or similar) to an appropriate section of your code:
MyButton1.Click += new RoutedEventHandler(buttons_Click);
MyButton2.Click += new RoutedEventHandler(buttons_Click);
etc...
You can associate as many controls to the event handler as you like.
What I usually do before is this:
private void button2_Click(object sender, EventArgs e)
{
button1.PerformClick();
}
This code will just simply run the codes under button1_Click.
But try not to practice as such and just simply put it in a function/method just like what David suggested.

flow panel with listview

I'm creating listviews in a flowpanel at run time which later will accept drag and dropped files. the reason being is i want these to act as folders so a user double clicks and gets a window displaying the contents.
i'm having difficulty setting up the events for my listviews as they are added.
how do i create some events (like MouseDoubleClick and DragDrop) dynamically for each added listview? can i create a single function for both of these events and have listview1, listview2, listviewX use it?
i have a button that is adding the listviews, which works fine. please advise, i apologize if this is too conceptual and not exact enough.
private void addNewWOButton_Click(object sender, EventArgs e)
{
ListView newListView = new ListView();
newListView.AllowDrop = true;
flowPanel.Controls.Add(newListView);
}
You would have to have the routine already created in your code:
private void listView_DragDrop(object sender, DragEventArgs e) {
// do stuff
}
private void listView_DragEnter(object sender, DragEventArgs e) {
// do stuff
}
and then in your routine, your wire it up:
private void addNewWOButton_Click(object sender, EventArgs e)
{
ListView newListView = new ListView();
newListView.AllowDrop = true;
newListView.DragDrop += listView_DragDrop;
newListView.DragEnter += listView_DragEnter;
flowPanel.Controls.Add(newListView);
}
You would have to check who the "sender" is if you need to know which ListView control is firing the event.
You can also just use a lambda function for simple things:
newListView.DragEnter += (s, de) => de.Effect = DragDropEffects.Copy;
Just make sure to unwire the events with -= if you also remove the ListViews dynamically.
To answer the other half of your question, you can use a single handler for any event, from any source, that has the handler's signature. In the body of the handler, you just have to check the sender argument to determine which control raised the event.
You need a way to tell one control from a different one of the same class, however. One way to do this is to make sure to set the Name property on each control when you create it; e.g., newListView.Name = "FilesListView".
Then, before you do anything else in your event handler, check the sender.
private void listView_DragDrop(object sender, DragEventArgs e) {
ListView sendingListView = sender as ListView;
if(sendingListView == null) {
// Sender wasn't a ListView. (But bear in mind it could be any class of
// control that you've wired to this handler, so check those classes if
// need be.)
return;
}
switch(sendingListView.Name) {
case "FilesListView":
// do stuff for a dropped file
break;
case "TextListView":
// do stuff for dropped text
break;
.....
}
}

Categories