Switch between panels - c#

I have 3 panels in 1 form to go through a process to input certain data. When the next button in a panel is clicked the next panel should be displayed.
Initially I have enabled the visibility of first panel and disabled the visibility of other panels.
When the next button is clicked the below code will be executed.
panel1.Visible = false;
panel2.Visible = true;
For the purpose of development I have put them side by side(not one upon another) and it woks perfect.
But when I put them one upon another the above code does not appear to be wok, which means when the next button is clicked it just shows a empty form.
Then I added below code too.
panel1.SendToBack();
panel2.BringToFront();
But it didn't work. Can someone help me with this.
Thank you.

This always goes wrong in the designer, the bottom panel will become the Parent of the top one. So if you hide the bottom one you can never see see the top one.
This can be worked around with View > (Other Windows) > Document Outline, drag the top panel back to the form. Still pretty painful, you typically have to edit the Location by hand and making any changes to the form in the designer later tends to slurp the panel back.
There are better ways to do this. Creating UserControls instead is highly recommended, they have their own design surface. Or use the RAD way and do this with a TabControl instead. All you have to do is hide the tabs at runtime, the subject of this Q+A.

You have to be careful when putting container controls like a Panel 'one upon another '.
In the designer you can do it, but only by carfully moving the panel with the keyboard. Using the mouse will always put the moved one into not upon the other one whenever its top left corner gets inside the other one.
As an alternative you can do the moving in code.
Doing it in code has the advantage of still being able to work with the lower panels and its content. Sometimes I stuff them into the tabpages of an (at runtime invisible) dummy tab and move it in or out of the pages to hide and show them..

Here is the code you can use to have multiple panels at the same time and switch between them with the next buttom added to the form.
public Form1()
{
InitializeComponent();
panel1.Visible = true;
panel3.Visible = false;
panel2.Visible = false;
}
private void btnNext_Click(object sender, EventArgs e)
{
if (panel1.Visible)
{
panel1.Visible = false;
panel2.Visible = true;
panel3.Visible = false;
}
else if (panel2.Visible)
{
panel1.Visible = false;
panel2.Visible = false;
panel3.Visible = true;
}
else if (panel3.Visible)
{
panel1.Visible = true;
panel2.Visible = false;
panel3.Visible = false;
}
}
Of course if you tagged your panels in ascending/descending format no gap between the tags for example 1,2,3,4 or 5,4,3,2 not 1,2,4 you could use this code
public Form1()
{
InitializeComponent();
panel1.Visible = true;
panel2.Visible = false;
panel3.Visible = false;
}
private void btnNext_Click(object sender, EventArgs e)
{
TogglePanels();
}
public void TogglePanels()
{
List<Panel> allPanelsInForm = new List<Panel>();
foreach (var control in Controls)
{
if (control is Panel)
allPanelsInForm.Add(control as Panel);
}
Panel visiblePanel = allPanelsInForm.Where(o => o.Visible).FirstOrDefault();
int nextPanelId = Convert.ToInt32(visiblePanel.Tag) + 1;
bool nextPanelExists = allPanelsInForm.Exists(o => Convert.ToInt32(o.Tag) == nextPanelId);
nextPanelId = nextPanelExists ? nextPanelId : 1;
foreach (Panel panel in allPanelsInForm)
{
panel.Visible = Convert.ToInt32(panel.Tag) == nextPanelId ? true : false;
}
}
I wish it could help you.

Related

Contents of a panel won't visually update within a given time, but will clear completely afterwards

I have a form with a picturebox docked to fill the whole thing. On this form, I have a panel that is normally invisible and another picturebox; on the panel, I have a label and another panel with a label.
Here is what SHOULD happen when the user hovers over the second picturebox:
The picturebox's image changes and the first panel becomes visible, making the second panel and both labels visible too
The user clicks on the second label
The second label's OnClick handler makes the first label's text change and the second panel becomes invisible
A timer ticks for a few seconds
A code segment in the timer's OnTick handler causes the image in the second picturebox to change and the first panel to become invisible
Here is what DOES happen:
The picturebox's image changes and the first panel becomes visible, making the second panel and both labels visible too
The user clicks on the second label
The second label's OnClick handler sets the first label's text to a new string and sets the second panel's Visible property to false, BUT the second panel stays visible (although you can't interact with it) and the first label's text gets written on top of the old text
A timer ticks for a few seconds
A code segment in the timer's OnTick handler causes the image in the second picturebox to change and the first panel to become invisible
I've tried everything I can think of. I've called Invalidate, Update, and Refresh on every control in the form, I've called Application.DoEvents, I've reset the image in the background PictureBox to itself, nothing. The REALLY weird part is that in step 5, when the front picturebox resets itself and all panels are set invisible, nothing gets left behind - it's just for that brief few seconds between the OnClick handler terminating and the timer's OnTick cleaning up that there are problems. I can edit this for more information if needed, but does anyone have any ideas of what to do?
Edit: It's been pointed out to me that I should probably upload the code for this. Well, that code is a hacked-together mess, but okay. Also: there are some weird extra bits (in the enum types among others), they're for later parts of the project and irrelevant right now.
bool CountingHoverTime = false;
int HoverTime = 0;
int MasterTick = 0;
enum GhostState { Stand, Speak, Pet, Ask };
GhostState curState;
public enum TalkType { HoverGen, Petted, Spont, TimerMsg, Response };
private void Form1_Load(object sender, EventArgs e)
{
FormBorderStyle = FormBorderStyle.None;
ShowInTaskbar = false;
TopMost = true;
ControlBox = false;
Text = String.Empty;
WindowState = FormWindowState.Maximized;
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
this.BackColor = Color.Transparent;
this.TransparencyKey = Color.Transparent;
}
protected override void OnPaintBackground(PaintEventArgs e)
{
//base.OnPaintBackground(e);
}
private void pictureBox2_MouseHover(object sender, EventArgs e)
{
if(curState == GhostState.Stand)
{
CountingHoverTime = true;
}
}
private void timer1_Tick(object sender, EventArgs e)
{
if((curState != GhostState.Ask) && (curState != GhostState.Stand))
{
MasterTick++;
if(MasterTick > 10)
{
SetToBasic();
}
}
else
{
MasterTick = 0;
}
if (CountingHoverTime)
{
HoverTime++;
if (HoverTime > 4)
{
HoverTime = 0;
curState = GhostState.Ask;
Say("What can I do for you?", TalkType.HoverGen);
}
}
}
public void SetToBasic()
{
curState = GhostState.Stand;
ghostBox.Image = Properties.Resources.stickStand1;
TalkPanel.Visible = false;
}
public void Say(String speak, TalkType type)
{
mainText.Text = speak;
if(type == TalkType.Response || type == TalkType.Spont)
{
curState = GhostState.Speak;
}
else
{
curState = GhostState.Ask;
}
ghostBox.Image = Properties.Resources.stickTalk;
if (type == TalkType.HoverGen)
OptionPanel.Visible = true;
else
OptionPanel.Visible = false;
TalkPanel.Visible = true;
backBox.Image = Properties.Resources.background;
ghostBox.Invalidate();
TalkPanel.Invalidate();
mainText.Invalidate();
backBox.Invalidate();
ghostBox.Update();
TalkPanel.Update();
mainText.Update();
backBox.Update();
Application.DoEvents();
}
private void op1label_Click(object sender, EventArgs e)
{
curState = GhostState.Speak;
OptionPanel.Visible = false;
Say("No can do yet.", TalkType.Response);
}
Edit 2: I've put together a gif visualization of what's happening, thank you HandbagCrab.
I've approached this from a different direction. I think the issue is to do with the picturebox you have docked on the form causing some issues.
To fix it and still keep the transparency, get rid of the backBox. Set the background colour of the form to a colour you're not going to use then set the transparency key to that colour. This will make those areas of the form transparent. Now you just need your hidden panel and your labels and whatever control it is that hosts your stick man image.
I've left the backgrounds of the labels as pink here but you should change them to your background colour so that they're not transparent.
When I run the form I get the transparency still and when clicking on the grey panel (I've used a panel to simulate your stick man) shows the hidden panel with the labels. Clicking label2 updates the text on label1 (the one that contains the text "longish text"), completely replacing the text.
Here it is in use (I've not done a gif as I wanted each step to be clearly visible)
Here's the application when open:
Here it is after clicking the grey box:
Here's the updated text when clicking label2:
I've left the application border style as Sizeable just so you can see where the border lies. I also took the screenshots over a black background so there was no visual clutter.
Here's me right clicking the desktop through the transparent section:

Panels behavior : separation

I have 3 panels on top of each others and 3 buttons. What I want to achieve is with every button click its correspondent panel appears, currently I am using panel.Visible = true; and panel.Visible = false; but since every element over a panel in a WFA is considered a child of that panel all I get is either they are all visible or they are all invisible.
Q: How to make each panel behave separately?
This is the visibility control code:
private void btnHome_Click(object sender, EventArgs e)
{
panelHome.Visible = true;
panelContact.Visible = false;
panelOther.Visible = false;
}
private void btnContact_Click(object sender, EventArgs e)
{
panelHome.Visible = false;
panelContact.Visible = true;
panelOther.Visible = false;
}
private void btnOther_Click(object sender, EventArgs e)
{
panelHome.Visible = false;
panelContact.Visible = false;
panelOther.Visible = true;
}
This issue is easly solved using the graphical user interface:
You just need to carefully place every panel on top of the previous one until the blue guidelines appear.
PS: You need to check 2 guidelines: one vertical (left or right) and one horizontal (top or bottom)

How to access parent form items from child form?

Hello Friends Please help me, I'm new to C# Programming. Kindly help me, I'm unable to integrate my project due to below problem.
I have created a MainScreen form, in that I took two panels. First Panel contains project name and a menustrip. In Second panel I'm loading different panels depending on what user click in menustrip. menustrip contain different elements like Home, Update Profile, Search, Book and Logout. By default I'm loading Home form in MainScreen 2nd panel. It kindoff looks like webpage. After logging successfully I want to clear the 2nd panel and want to load Home form/Search form. But when I try to do it, it shows "U cant access panel2 in this context". Please help me, I'm tired of searching solution for it. If this way is not possible, provide me some alternate way. Thanks in Advance!
I used below code...I made mdi parent true too.
private void homeToolStripMenuItem_Click(object sender, EventArgs e)
{
Home ob1 = new Home();
ob1.TopLevel = false;
ob1.FormBorderStyle = FormBorderStyle.None;
pnlBody.Controls.Clear();
pnlBody.Controls.Add(ob1);
ob1.Show();
}
private void MainScreen_Load(object sender, EventArgs e)
{
MainMenuStrip.Items[5].Visible = false;
Home ob1 = new Home();
ob1.TopLevel = false;
ob1.FormBorderStyle = FormBorderStyle.None;
pnlBody.Controls.Clear();
pnlBody.Controls.Add(ob1);
ob1.Show();
}
You can simply do this by assigning that control Modifier to public. but, it is not a good way to do this. Don't do this. If you want to execute any specific code from the outside the form than you can create a separate method and then create delegate for that method. you can invoke that method by using delegate.Invoke. I have already suggested that in my previous answer.
Let's imagine you have these controls which are from your main page:
button1
textbox1
label1
Now when you click a menu option you need to hide some or all of the controls above and then show these ones:
button2
textbox2
picturebox1
label2
If you want this, then you can just make this in the click event without using panels:
private void homeToolStripMenuItem_Click(object sender, EventArgs e)
{
button1.Visible = false;
textbox1.Visible = false;
label1.Visible = false;
button2.Visible = true;
textbox2.Visible = true;
picturebox1.Visible = true;
label2.Visible = true;
button1.Location = new Point(X, Y);
//Other controls locations...
}
Where the new Point is a class constructor that allows you to change the position of a control in the form (X and Y are pixel coordinates)
And... I guess that's all ~ :3
Ohhh and you could use a public int to count the page number... So if you have for example 3 pages, when the user click, I don't know "Page 2" your variable X which is public will have the value of 2, so in your event you can compare page combinations:
private void homeToolStripMenuItem_Click(object sender, EventArgs e)
{
if(x==1)//You know you are un page 1, you hide all the page 1 controls
{
button1.Visible = false;
textbox1.Visible = false;
label1.Visible = false;
}
else if(x==2)
{
//Hide you page 2 control, etc.
}
//After hidding your controls, next you have to show this page controls and adjust them to the form which are this ones:
button2.Visible = true;
textbox2.Visible = true;
picturebox1.Visible = true;
label2.Visible = true;
button1.Location = new Point(X, Y);
//Other controls locations...
//Finally, set X the value of the page number so you can copy and paste te comparation os X above in your events of every page:
X = pagenumber;
}

How to expand the picturebox into another form?

Currently, my application displays 6 picture boxes, each displaying an picture which is being constantly updating.
Now, I want upon clicking any picture box that picture box extends and fill up the whole screen just showing that chosen picture box.
Is this possible? Must i create another form to do this?
Thanks In Advance,
Perumal
in the onclick event for each the picture box (they can all point to this same method)
picturebox_Click(object sender .....)
{
PictureBox pb= (PictureBox)sender;
if (pb.dock==DockStyle.None)
{
pb.dock=DockStyle.Fill;
pb.BringToFront();
}
else
pb.dock=DockStyle.None;
}
Not seeing any code, here is how you can programmatically change a picture box on click.
pictureBox1.Dock = DockStyle.Fill
So you need to create a on click event handler and call your picture box's Dock function like the above.
update in response to comments
There is a DockStyle.None to revert the picture back to original size.
If i understand you correctly, you want to have 6 pictures and then when you click one it fills, click again, shrinks, click another one, fills etc etc...
To do this, you would use the Dock and Visible properties on the picture boxes. Now it also seems as if you are asking how to actually write the code. Well if you show some code, I could give pointers, with nothing to go on the way I'd approach it is to:
Put all your picture boxes in a list and assign a state to them Big or Small.
Write a OnClick for each picture box to change the state of the picture box clicked on.
Each OnClick then calls a helper function that iterates through each picture box in the list and hides the small one and DockStyle.Fill the big one.
Does the above algorithm accomplish what you need?
try something like this. the code is not re factored but I am sure you can do that
private bool isfill = false;
private void pictureBox1_Click(object sender, EventArgs e)
{
if (!isfill)
{
pictureBox1.Dock = DockStyle.Fill;
pictureBox2.Visible = false;
isfill = true;
}
else
{
pictureBox1.Dock = DockStyle.None;
pictureBox2.Visible = true;
isfill = false;
}
}
private void pictureBox2_Click(object sender, EventArgs e)
{
if (!isfill)
{
pictureBox2.Dock = DockStyle.Fill;
isfill = true;
pictureBox1.Visible = false;
}
else
{
pictureBox2.Dock = DockStyle.None;
isfill = false;
pictureBox1.Visible = true;
}

Select Tab Page in TabControl without stealing focus

Using TabControl.SelectTab("...") shows the tab but it also gives the tab focus. I would like to show a particular tab, but keep focus where it is.
I have data rows in a grid. Based on properties of the selected row, I show a different tab page to have a different UI layout. But when using arrow keys to scroll through rows, the focus switches to the selected tab -- which I don't want to happen.
Thanks.
You can try disabling the TabControl before setting the selected tab, then re-enabling it. This will prevent it from taking focus. I tested this on a tab control with a few controls on it, and didn't see any visual change, but you'll have to try it in your UI and see whether it's ok for you.
tabControl1.Enabled = false;
tabControl1.SelectTab("tabPage4");
tabControl1.Enabled = true;
To be safe, you could put the line to re-enable the TabControl in a finally block to make sure it doesn't get left disabled.
I don't think there's a built-in function, but you can do in this way:
private bool skipSelectionChanged = false;
private void dataGridView_SelectionChanged(object sender, EventArgs e)
{
if (skipSelectionChanged)
return;
// supposing we decide tab[0] has to be selected...
this.SelectTabWithoutFocus(this.tabControl1.TabPages[0]);
}
private void SelectTabWithoutFocus(TabPage tabPage)
{
this.skipSelectionChanged = true;
// "this" is the form in my case, so you get the current focused control
// (ActiveControl), backup it, and re-set it after Tab activation
var prevFocusedControl = this.ActiveControl;
if (this.ActiveControl != null)
{
this.tabControl1.SelectedTab = tabPage;
prevFocusedControl.Focus();
}
this.skipSelectionChanged = false;
}
Here, I backup the current focused control, select the desired tab, and finally set the focus to the original control.
Skipping boolean is necessary, because giving the focus to the grid you trigger SelectionChanged event again, causing infinite looping.
This selects the tab pages while keeping the focus on top, as asked here above:
tc.TabPages[0].Enabled = false;
tc.SelectTab(0);
tc.TabPages[0].Enabled = true;
tc is here my instance for the TabControl type (i. e. it IS my tab control, and it has a few "tab pages"). This works properly for me. My purpose is to loop through these tab pages with the Left and Right keys (arrows) i. e. when I go forwards (by Key.Right) and reach the last tabpage I want to have my focus on [0] without activating the DataGridView which I have in that page, and when I go backwards (by Key.Left) and reach [0] I want to have [tc.TabCount - 1] enabled, which is the last one. The code for this case is:
tc.TabPages[tc.TabCount - 1].Enabled = false;
tc.SelectTab(tc.TabCount - 1);
tc.TabPages[tc.TabCount - 1].Enabled = true;
The complete piece of code is:
private bool KeyTc(System.Windows.Forms.Keys keyData)
{
if (keyData == K.Left && tc.SelectedIndex == 0)
{
tc.TabPages[tc.TabCount - 1].Enabled = false;
tc.SelectTab(tc.TabCount - 1);
tc.TabPages[tc.TabCount - 1].Enabled = true;
return true;
}
else if (keyData == K.Right && tc.SelectedIndex == tc.TabCount - 1)
{
tc.TabPages[0].Enabled = false;
tc.SelectTab(0);
tc.TabPages[0].Enabled = true;
return true;
}
return false;
}
This bool KeyTc is returned to a case in a switch statement for key evaluation in:
protected override bool ProcessCmdKey(ref Message keyMsg, Keys keyData)
{ switch keyData { ... } }
Base on the solution proposed by "Jeff Ogata : You can try disabling the TabControl before setting the selected tab, then re-enabling it. This will prevent it from taking focus", here bellow my solution:
tabMain.SelectedPageChanging += (s, e) =>
{
tabMain.Enabled = false;
};
tabMain.SelectedPageChanged += (s, e) =>
{
tabMain.Enabled = true;
};
Note: this code is using DevExpress "DevExpress.XtraTab.XtraTabControl".

Categories