I have searched but cannot locate this problem.
On form 1 in code, I create a TabPage with a usercontrol in it and then add the TabPage to form1.TabControl and call public method LoadData on the usercontrol.
Problem: I need to reload the data when the new tabpage is activated or gains focus. If I did not create the tabpage in code, I could simply use TabControl's selectedIndex change event, but it needs to be created in code.
How can I do this? Form 1:
private void CreateNewTab()
{
TabPage tp1 = new TabPage();
tp1.Text = "HSV";
tp1.Name = "tpHSV";
if (tabContMain.TabPages.ContainsKey(tp1.Name) == false)
{
HSVControl hsvc = new HSVControl();
hsvc.Dock = DockStyle.Fill;
hsvc.LoadData();
tp1.Controls.Add(hsvc);
tabContMain.TabPages.Add(tp1);
}
}
====EDIT===============
Thanks for the comments. Let me try to explain my problem better. The selectedIndex change event works fine. I can access the tab by it's text or name. The problem is calling the hsvc.LoadData() method. I need to recall this method when the tab containing hsvc user control is clicked. The LoadData() is public, but I cannot find a way to access it in Form1 (which holds the selectedIndex change event). I need a reference to hsvc control.
I added a property to the Form1 class like this:
private UserControl mControl;
then assigning it:
HSVControl hsvc = new HSVControl();
hsvc.Dock = DockStyle.Fill;
hsvc.LoadData();
mControl=hsvc;
Then calling it in SelectedIndex change event, but it is still not visible there.
Ok, thanks again for the help. The solution was kind of staring me in the face. I'm not sure it's the best, but this worked very well.
Created interface:
public interface IControlBase
{
void LoadData();
}
Had UserControl implement interface:
HSVControl : UserControl,IControlBase
and having the existing LoadData() method on the usercontrol.
change
private UserControl mControl;
to
private IControlBase mControl;
Then in SelectedIndex change:
mControl.LoadData();
TabControl Has a property called SelectedTab. use that property like:
private void CreateNewTab()
{
TabPage tp1 = new TabPage();
tp1.Text = "HSV";
tp1.Name = "tpHSV";
if (tabContMain.TabPages.ContainsKey(tp1.Name) == false)
{
HSVControl hsvc = new HSVControl();
hsvc.Dock = DockStyle.Fill;
hsvc.LoadData();
tp1.Controls.Add(hsvc);
tabContMain.TabPages.Add(tp1);
tabContMain.SelectedTab = tp1;
}
}
In that last line, It makes the TabControl to call its SelectedIndexChanged event. Then call LoadData event in this event:
private void TabControl_SelectedIndexChangedEvent(object sender, EventArgs e)
{
//So Because Hsvc is a public field. I call its method here:
if(TabControl.SelectedTab.Name = "My Desired Tab";
{
hsvc.LoadData();
}
}
Related
I have extended the Label class as follows:
public class MyLabel: Label {
public Button btn;
public string mydata;
}
In my main program, I instantiated a new instance:
MyLabel lbl = new MyLabel();
lbl.mydata = "some data here";
lbl.btn = new Button();
lbl.btn.Click += new EventHandler(button_pressed);
this.Controls.Add(lbl); // Adds the label to the form
this.Controls.Add(lbl.btn); // Adds the button to the form
And I created a method to handle the button click event:
void button_pressed(Object sender, EventArgs e) {
Button btn = (Button)sender;
//Now I have an access to the property within MyLabel instance.
// but how can I access the parent object?
// I need to access the sibling property [mydata] string from here
btn.Siblings["mydata"] = "some other thing" ; //Something like this
MyLabel lbl = btn.ParentObject(); //Or something like this
lbl.mydata = "Some other thing";
}
This looks like WinForms, in which case either a UserControl or extending Button class might be a good way to go - just maintain a reference to the parent (a bit more complicated with UserControl, you'd need to define the click event on that control, otherwise you're back to "square 1") I like the Tag property solution as well, although there is an additional cast, and no guarantee of type safety (since Tag is an object, it can be anything by the time you try to access it).
However, let's say you're looking for a more general solution; let's also say that the class in question is sealed, has no Tag or similar purpose property, and a Controls collection is not available (or looping through it is not desirable for performance reasons). To my best knowledge, you can't determine parent object; but you can easily provide your own "Controls" style dictionary, mapping the Button to the parent:
public class MyLabel: Label {
public static Dictionary<Button, MyLabel> ParentMap = new Dictionary<Button, MyLabel>();
public Button btn;
public string mydata;
public void AddToParentMap() => ParentMap[btn] = this;
}
When you're creating an instance of MyLabel, just call the AddToParentMap() function (can't be done in constructor, because this pointer is not available until the object is created):
MyLabel lbl = new MyLabel();
lbl.AddToParentMap();
You can then just look it up, fast and easy, in your click event:
void button_pressed(Object sender, EventArgs e) {
Button btn = (Button)sender;
var label = MyLabel.ParentMap[btn];
//...
//Your code...
}
Unlike the Tag solution, type safety is guaranteed - you always know you're accessing a MyLabel object.
You can't access it through button instance but what you can do is to get MyLabel from Controls collection:
var lbl = this.Controls.OfType<MyLabel>().FirstOrDefault(c => c.btn == btn);
You can use the Tag property.
lbl.btn = new Button();
lbl.btn.Tag = lbl;
And then when you need it:
Button btn = (Button)sender;
Label lbl = (MyLabel)btn.Tag;
I started out C# very recently and sorry if this question sounds dumb.
How do I add a Listbox in a Form that pops out from a Button click?
Note: The Form isn't the one that's added from the Solution Explorer whereby I can just drag a Listbox from the Toolbox to my Form.
So what I want is to create a ListBox in my file drawer1Form where I can add additional items. Thanks for the help in advance!:)
private void drawer1button_Click(object sender, EventArgs e) // Drawer 1 Button
{
drawer1Form df1 = new drawer1Form();
df1.StartPosition = FormStartPosition.CenterScreen;
df1.Show();
}
public partial class drawer1Form : Form // Creates drawer1Form
{
public drawer1Form()
{
Text = "Drawer 1 ";
}
}
Pretty much the same way as you'd do with any other object.
In the class of your form add a
private ListBox myAwesomeListBox;
Then in the button event handler add something like this:
myAwesomeListBox = new ListBox();
myAwesomeListBox.SuspendLayout();
// set all the properties that you want
myAwesomeListBox.Name = "myAwesomeListBox";
myAwesomeListBox.Location = new Point(...); // place it somewhere
myAwesomeListBox.Size = new Size(...); // give it a size
// etc...
df1.Controls.Add(myAwesomeListBox);
myAwesomeListBox.ResumeLayout();
This should be it.
I highly advise you to do it through the designer first though, and then take a look at the generated code in the form's .Designer.cs file, you'll have a very good understanding after reading through that.
I have a TabControl with three TabPages. The initial start of the app opens always the first TabPage on the left side. For me it's necessary to set the starting TabPage (for example the second one).
Of course, I know about possibilities to change the tab on start like these:
tabControl.SelectedTab = tabPage;
tabControl.SelectTab(tabPage);
...
But this code would also activate additional events to fire like TabControl.Selecting, TabControl.Deselecting, TabControl.SelectedIndexChanged etc. — I would really like to prevent this in advance.
What I am looking for is some kind of property in the TabControl like "StartingTabPageIndex" - setting it to 1 would open the second TabPage on start without invoking any unnecessary events.
Another option. Go into the Form Designer, change the SelectedIndex property from 0 to 1:
//
// tabControl1
//
this.tabControl1.Controls.Add(this.tabPage1);
this.tabControl1.Controls.Add(this.tabPage2);
this.tabControl1.Controls.Add(this.tabPage3);
this.tabControl1.Location = new System.Drawing.Point(223, 21);
this.tabControl1.Name = "tabControl1";
this.tabControl1.SelectedIndex = 1; // <-- This Line
this.tabControl1.Size = new System.Drawing.Size(300, 143);
this.tabControl1.TabIndex = 3;
The event handlers aren't connected yet, and making any modifications to the TabControl in the designer doesn't seem to affect that property. It seems safe to change it this way.
You should remove the binding with the event handlers from the designer and add them after you have set the initial tabpage
After removing them in the designer (this doesn't delete the event handler code) rebind the event handler in the form load event after setting the required tabpage
tabControl.SelectedTab = tabPage;
tabControl.Selected += tabControl_Selected;
.... and so on for the other events to handle....
Update
I just made a simple test, and SelectedTab does not work because it expects the handle to be created on set.
However this seems to work:
public class MyTabControl : TabControl
{
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[Browsable(true)]
public new int SelectedIndex
{
get { return base.SelectedIndex; }
set { base.SelectedIndex = value; }
}
}
You'll now be able to see SelectedIndex in the designer and can set it. It won't change the visible tab in the designer, but it will store the "initial tab index" (zero-based).
It does change SelectedIndex, but it does not call the events since events are assigned last in the designer's serialization, so they are never assigned before the change.
Old
One option would be having SelectedTab serialized. You'd only need to derive your own custom TabControl from TabControl and have something like this:
public class MyTabControl : TabControl
{
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public new TabPage SelectedTab {
get { return base.SelectedTab; }
set { base.SelectedTab = value; }
}
}
That way you'll get your designer selected SelectedTab as initial.
I haven't tested this, but theory says it should work :-)
I have a C# WPF app that every time the user opens a new file, the contents are displayed in a datagrid.
public partial class MainWindow : Window
{
public TabControl tc = new TabControl();
public MainWindow()
{
InitializeComponents();
}
private FromFile_click(object sender, RoutedEventArgs e)
{
//gets information from file and then...
if (numberOfFiles == 0)
{
masterGrid.Children.Add(tc);
}
TabItem ti = new TabItem();
tc.Items.Add(ti);
DataGrid dg = new DataGrid();
ti.Content = dg;
dg.Name = "Grid"+ ++numberOfFiles;
dg.ItemSource = data;
}
private otherMethod(object sender, RoutedEventArgs e)
{
}
}
My question is, how do I use the data in dg in the method "otherMethod"? Also, is it possible to change the parent of dg from the method "otherMethod"?
Assuming you're not calling otherMethod within FromFile_Click, you need to make it an instance variable - like your TabControl is, except hopefully not public. I'm assuming otherMethod is actually meant to handle an event of some kind, rather than being called directly.
Now this is assuming that you want one DataGrid per instance of MainWindow, associated with that window. If that's not the case, you'd need to provide more information.
You have to pass it as a parameter to the other method otherMethod or make it a member variable.
set the DataGrid dg as a property instead of declaring inside the FromFile_click.
This way when you assign "dg" it will work from any other method (few restrictions apply)
Does anyone know a way to open a 2nd form in a .NET application with a certain tab selected in a tab control on that form?
This is what my current code looks like which just opens the form:
SettingsForm TheSettingsForm = new SettingsForm(this);
TheSettingsForm.Show();
SettingsForm.cs is the name of the 2nd form to be opened.
Thanks in advance,
You just need to expose a property on your form that allows the calling code to set the desired tab. You might do it just by index like this:
var form = new SettingsForm(this);
form.SelectedTab = 2;
form.Show();
The property on the form would just set the appropriate property on the tab control:
public int SelectedTab
{
get { return _tabControl.SelectedIndex; }
set { _tabControl.SelectedIndex = value; }
}
Do something like this:
SettingsForm TheSettingsForm = new SettingsForm(this);
TheSettingsForm.TabPanel.SelectedIndex = SettingsFormTabIndexes.MyDesiredTab;
TheSettingsForm.Show();
where you've made a property in TheSettingsForm that exposes the tab control and SettingsFormTabIndexes is a friendly enum naming all the tabs by index.
Add an event handler to the TabControl.SelectedIndexChanged event.
myTabControl.SelectedIndexChanged += myTabControl_SelectedIndexChanged;
private void myTabControl_SelectedIndexChanged(object sender, EventArgs e) {
TabControl tc = sender as TabControl;
if (tc.SelectedIndex == indexOfTabToShowFormOn) {
TheSettingsForm.Show();
}
}