Switching Panels via Index Methods - c#

I've been trying to solve my issue for quite a while and to be honest am getting nowhere. What i would like is when the user clicks the 'top' button on my panel it automatically goes to the top( and swaps with the one there.) and when they click the bottom button it automatically goes to the bottom. I'm setting the index panel manually but of course this doesnt work because its only viable for one panel (i have ten). Greatly appreciate some help in finding a method that can send the panel to the top of the stack regardless of its position.
Here is a image (basic) to help understand
Control ctrlToMove = (Control)this.bookControls[bookName];
int ctrlToMoveIndex = bookPanel.Controls.IndexOf(ctrlToMove);
int ctrlToSwapIndex = ctrlToMoveIndex - 5;
Control ctrlToSwap = bookPanel.Controls[ctrlToSwapIndex];
this.bookPanel.Controls.SetChildIndex(ctrlToMove, ctrlToSwapIndex);
this.bookPanel.Controls.SetChildIndex(ctrlToSwap, ctrlToMoveIndex);

Based on your drawing, I made a UserControl with a button on it:
void uc_ButtonClicked(object sender, EventArgs e) {
UserControl1 uc = sender as UserControl1;
if (uc != null) {
int childIndex = flowLayoutPanel1.Controls.GetChildIndex(uc);
if (childIndex > 0) {
UserControl1 ucTop = flowLayoutPanel1.Controls[0] as UserControl1;
flowLayoutPanel1.Controls.SetChildIndex(uc, 0);
flowLayoutPanel1.Controls.SetChildIndex(ucTop, childIndex);
}
}
}

According to your picture you have one control per row in panel. Thus I suggest you to use TableLayoutPanel instead of FlowLayoutPanel. Also I'd create user control for items in panel. E.g. it will have name PriorityUserControl and four buttons to increase, decrease, maximize, minimize it's 'priority' (I placed buttons horizontally just to save place on screen):
Next, create four events in this user control:
public event EventHandler PriorityMaximized;
public event EventHandler PriorityIncreased;
public event EventHandler PriorityDecreased;
public event EventHandler PriorityMinimized;
And rise appropriate event when button clicked:
private void topButton_Click(object sender, EventArgs e)
{
if (PriorityMaximized != null)
PriorityMaximized(this, EventArgs.Empty);
}
That's it. We have user control which tells whether it want to move up or down. Now add user controls to TableLayoutPanel (either manually or dynamically) and subscribe same event handlers of these four events to ALL user controls. Something like:
// create user control and attach event handlers
PriorityUserControl control = new PriorityUserControl();
control.PriorityMaximized += priorityUserControl_PriorityMaximized;
control.PriorityMinimized += priorityUserControl_PriorityMinimized;
control.PriorityIncreased += priorityUserControl_PriorityIncreased;
control.PriorityDecreased += priorityUserControl_PriorityDecreased;
// add another row to table
panel.RowStyles.Add(new RowStyle(SizeType.AutoSize));
panel.RowCount = panel.RowStyles.Count;
// add control table layout panel
panel.Controls.Add(control);
panel.SetRow(control, panel.RowCount - 1);
Good. All you should do now is implement these event handlers. It's simple. E.g. decreasing priority (i.e. moving down):
private void priorityUserControl_PriorityDecreased(object sender, EventArgs e)
{
// sender is a control where you clicked Down button
Control currentControl = (Control)sender;
// get position in panel
var position = panel.GetPositionFromControl(currentControl);
// just to be sure control is not one at the bottom
if (position.Row == panel.RowCount - 1)
return;
// we want to switch with control beneath current
Control controlToSwitch = panel.GetControlFromPosition(0, position.Row + 1);
// move both controls
panel.SetRow(currentControl, position.Row + 1);
panel.SetRow(controlToSwitch, position.Row);
}
Now implementation of maximizing priority (i.e. moving to top):
private void priorityUserControl_PriorityMaximized(object sender, EventArgs e)
{
Control currentControl = (Control)sender;
var position = panel.GetPositionFromControl(currentControl);
if (position.Row == 0 || panel.RowCount < 2)
return;
Control topControl = panel.GetControlFromPosition(0, 0);
panel.SetRow(currentControl, 0);
panel.SetRow(topControl, position.Row);
}
I believe you will create rest two handlers by yourself.

The key of what you want is setting up a clear and extendable algorithm capable to deal with the different positions of the Panels. Here you have a simple code showing certain approach to this problem:
public partial class Form1 : Form
{
int[] panelLocations;
Point[] pointLocations;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
panelLocations = new int[5];
pointLocations = new Point[5];
panelLocations[1] = 1;
panelLocations[2] = 2;
panelLocations[3] = 3;
pointLocations[1] = new Point(panel1.Left, panel1.Top);
pointLocations[2] = new Point(panel2.Left, panel2.Top);
pointLocations[3] = new Point(panel3.Left, panel3.Top);
}
private void relocate(int curPanel, bool goTop)
{
int curLoc = panelLocations[curPanel];
int newLoc = curLoc - 1;
if (!goTop)
{
newLoc = curLoc + 1;
}
if (newLoc < 1) newLoc = 3;
if (newLoc > 3) newLoc = 1;
if (newLoc != curLoc)
{
int otherIndex = Array.IndexOf(panelLocations, newLoc);
panelLocations[curPanel] = newLoc;
relocatePanel(curPanel);
panelLocations[otherIndex] = curLoc;
relocatePanel(otherIndex);
}
}
private void relocatePanel(int curIndex)
{
if (curIndex == 1)
{
panel1.Location = pointLocations[panelLocations[1]];
}
else if (curIndex == 2)
{
panel2.Location = pointLocations[panelLocations[2]];
}
else if (curIndex == 3)
{
panel3.Location = pointLocations[panelLocations[3]];
}
}
private void buttonTop1_Click(object sender, EventArgs e)
{
relocate(1, true);
}
private void buttonBottom1_Click(object sender, EventArgs e)
{
relocate(1, false);
}
}
Open a new project, add 3 panels (Panel1, Panel2 and Panel3... better put different background colors) and include two buttons (buttonUp and buttonDown). This code will make the Panel1 to go up and down (by changing its position with the other panels).
The idea is pretty simple: at the start you store the positions of all the Panels in an array. In another array, you store where each panel is located every time (1 is the original position of Panel1, etc.).
It is a quite simple code which you can improve and extend as much as required, but the idea is pretty reliable and you can use it in any case: a set of fixed positions through which the panels will be moving.

Related

Loading multiple Groupboxes in the form using the button_click event

I wish to load multiple groupboxes in the windows form application using a button_click event.
A groupbox should appear in the form each time the button is clicked.
Expected output.
I am having trouble making the location of the groupbox dynamic, as the second groupbox should be some distance away from the first groupbox. I thought of manually calculating the coordinates and using an array of points for the location, but I feel that there should be a better a way to go about it.
I have defined 'int count=0' variable to count the number of times the button is clicked. Based on that I am naming the new groupbox. But I think there is some problem in the logic used in the count++ line. It is not going after 1. Therefore I am only getting one groupbox "groupBox1". Nothing happens when I click the button again.
I appreciate your help.
Thank you
int count=0;
private GroupBox GetGroupBox(int a)
{
GroupBox groupBox = new GroupBox();
groupBox.Text = "groupBox"+(a.ToString());
groupBox.Width= 200;
groupBox.Height= 200;
groupBox.Location = new Point(50,400);
return groupBox;
}
private void button1_Click(object sender, EventArgs e)
{
count++;
this.Controls.Add(GetGroupBox(count));
}
Your question states these objectives:
Dynamically add a GroupBox based on an event (like button click).
Assign the new GroupBox location.
Pad the location with "some distance away".
You say you "feel that there should be a better a way to go about it" and there is!
Try experimenting with a FlowLayoutPanel which handles all three of these by its nature.
Here's the code I used to add and remove instances of CustomGroupBox. This is a UserControl that I added to my project, but this will work with any type of control.)
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
numericUpDownGroupboxes.ValueChanged += onGroupBoxCountChanged;
foreach (var radio in Controls.OfType<RadioButton>())
{
radio.CheckedChanged += onFlowLayoutDirectionChanged;
}
}
When the numeric up-down changes, compare the expected number of groupboxes to the current count. Alternatively, you can continue to use a button click and go straight to flowLayoutPanel.Controls.Add(...).
private void onGroupBoxCountChanged(object sender, EventArgs e)
{
// Need an int for comparison.
int
countIs = flowLayoutPanel.Controls.OfType<CustomGroupBox>().Count(),
countShouldBe = (int)numericUpDownGroupboxes.Value;
switch(countIs.CompareTo(countShouldBe))
{
case -1:
flowLayoutPanel.Controls.Add(
new CustomGroupBox
{
Name = $"groupBox{countShouldBe}",
Text = $"GroupBox {countShouldBe}",
Size = new Size(300, 150),
Margin = new Padding(10),
BackColor = Color.White,
});
break;
case 1:
Control last = flowLayoutPanel.Controls.OfType<CustomGroupBox>().Last();
flowLayoutPanel.Controls.Remove(last);
break;
}
}
The direction of the flow can also be specified.
private void onFlowLayoutDirectionChanged(object sender, EventArgs e)
{
if(radioButtonHorizontal.Checked)
{
flowLayoutPanel.FlowDirection = FlowDirection.LeftToRight;
}
else
{
flowLayoutPanel.FlowDirection = FlowDirection.TopDown;
}
}
}
Since you want to create boxes from left to right you should adjust Left: say, 1st box should have Left = 50, 2nd Left = 270, 3d Left = 490 etc.
Code:
const int deltaX = 20;
...
//TODO: check do you really want Top = 400, not, say, 20?
groupBox.Location = new Point(50 + (a - 1) * (groupBox.Width + deltaX), 400);
...
Simplified implementation can be
int count = 0;
// Let's rename the method: we actually create GroupBox, not get existing
private GroupBox CreateGroupBox(int index) => new GroupBox() {
Text = $"groupBox{index}",
Size = new Size(200, 200),
Location = new Point(50 + (index - 1) * (20 + 200), 400),
Parent = this, // Instead of Controls.Add()
};
private void button1_Click(object sender, EventArgs e) {
CreateGroupBox(++count);
}

Add dynamically added textbox value from User Control to main form

In my main form I have a textbox namely textBoxTotalTotal and I want all the dynamically added textbox to be the added/sum in my textBoxTotalTotal How can I achieve that?
In my main form I have this:
textBoxTotalTotal
Then in my User Control I have this
public void textBoxTranspo_TextChanged(object sender, EventArgs e)
{
int intTranspo = 0, intBoxDaily = 0;
if (int.TryParse(textBoxTranspo.Text, out intTranspo) && int.TryParse(textBoxDaily.Text, out intBoxDaily))
textBoxTotalAmount.Text = (intTranspo + intBoxDaily).ToString();
}
and
public void textBoxDaily_TextChanged(object sender, EventArgs e)
{
int intTranspo = 0, intBoxDaily = 0;
if (int.TryParse(textBoxTranspo.Text, out intTranspo) && int.TryParse(textBoxDaily.Text, out intBoxDaily))
textBoxTotalAmount.Text = (intTranspo + intBoxDaily).ToString();
}
Note that I am dynamically adding that User Control via button in the main form as many times I like. So the textBoxTotalTotal should just add them up wheter a new 2 textbox comes up.
Assuming that UserControls' Parent is Form1 and User Control type MyUserControl:
(You should set the correct parent, and user control type)
MyUserControl[] controls = Form1.Controls.OfType<MyUserControl>().ToArray();
int Total = 0;
for(int i=0;i<controls.Length;i++){
controls[i].Controls.OfType<TextBox>().ToList()
.ForEach(txt => Total += int.Parse(txt.Text));
}
If you are doing it from the UserControl itself then:
MyUserControl[] controls = Parent.Controls.OfType<MyUserControl>().ToArray();
int Total = 0;
for(int i=0;i<controls.Length;i++){
controls[i].Controls.OfType<TextBox>().ToList()
.ForEach(txt => Total += int.Parse(txt.Text));
}

TabPage title alignment being wrong after drag'n'dropping

I have the class that extends System.Windows.Forms.TabControl and had implemented drag'n'drop mechanism for its TabPages as following:
#region Overriden base methods
protected override void OnDragOver(DragEventArgs e)
{
if (PointedTabPage == null) return;
e.Effect = DragDropEffects.Move;
var dragTab = e.Data.GetData(typeof (ManagedTabPage)) as ManagedTabPage;
if (dragTab == null) return;
int dropIndex = TabPages.IndexOf(PointedTabPage);
int dragIndex = TabPages.IndexOf(dragTab);
if (dragIndex == dropIndex) return;
var modifiedTabPages = new List<ManagedTabPage>(from ManagedTabPage tabPage in TabPages
where TabPages.IndexOf(tabPage) != dragIndex
select TabPages[TabPages.IndexOf(tabPage)] as ManagedTabPage);
modifiedTabPages.Insert(dropIndex, dragTab);
for (byte i = 0; i < TabPages.Count; ++i)
{
var managedTabPage = TabPages[i] as ManagedTabPage;
if (managedTabPage != null && managedTabPage.Uid == modifiedTabPages[i].Uid)
continue;
TabPages[i] = modifiedTabPages[i];
}
SelectedTab = dragTab;
}
protected override void OnMouseDown(MouseEventArgs e)
{
try
{
switch (e.Button)
{
case MouseButtons.Left:
DoDragDrop(PointedTabPage, DragDropEffects.Move);
break;
case MouseButtons.Middle:
CloseTab(PointedTabPage);
break;
}
}
catch (InvalidOperationException)
{
}
finally
{
TabPages.Insert(0, String.Empty);
TabPages.RemoveAt(0);
}
}
#endregion
Nota bene that in the finally clause of OnMouseDown method there are 2 lines for workarounding the
problem: for some reason w/o these lines after drag'n'dropping any of TabPages alignment of their titles is being wrong:
What should I do to correct this behavior without this smelly workaround? Maybe sending some Windows messages could do the trick?
Thanks a lot for any suggestions.
Edit 1. Code of ManagedTabPage is 100% unimportant (it's just extends TabPage with some specific properties).
PointedTabPage is unimportant too, but this is it:
return (from ManagedTabPage tabPage in TabPages
let tabPageIndex = TabPages.IndexOf(tabPage)
where GetTabRect(tabPageIndex).Contains(PointToClient(Cursor.Position))
select TabPages[tabPageIndex]).Single() as ManagedTabPage;
I'm trying to achieve fully-centered alignment of labels. You see, labels on the screenshot didn't centered horizontally?
I can't do much with the posted code. Let's take a completely different tack and create a tabcontrol that supports dragging a tabpage with the mouse. Add a new class to your project and paste this code:
using System;
using System.Drawing;
using System.Windows.Forms;
class TabControlEx : TabControl {
private Point downPos;
private Form draggingHost;
private Rectangle draggingBounds;
private Point draggingPos;
public TabControlEx() {
this.SetStyle(ControlStyles.UserMouse, true);
}
}
The usage of the variable becomes clear later. First thing we need is to get mouse events from the TabControl so we can see the user trying to drag a tab. That requires turning on the UserMouse control style, it is off by default for controls (like TabControl) that are built-in Windows controls and use their own mouse handling.
Use Build > Build and drag the new control from the top of the toolbox onto a form. Everything still looks and acts like a regular TabControl, but do note that clicking tabs no longer changes the active tab. A side-effect of turning the UserMouse style on. Let's fix that first, paste:
protected override void OnMouseDown(MouseEventArgs e) {
for (int ix = 0; ix < this.TabCount; ++ix) {
if (this.GetTabRect(ix).Contains(e.Location)) {
this.SelectedIndex = ix;
break;
}
}
downPos = e.Location;
base.OnMouseDown(e);
}
We are storing the click location, that's needed later to detect the user dragging the tab. That requires the MouseMove event, we need to start dragging when the user moved the mouse far enough away from the original click position:
protected override void OnMouseMove(MouseEventArgs e) {
if (e.Button == MouseButtons.Left && this.TabCount > 1) {
var delta = SystemInformation.DoubleClickSize;
if (Math.Abs(e.X - downPos.X) >= delta.Width ||
Math.Abs(e.Y - downPos.Y) >= delta.Height) {
startDragging();
}
}
base.OnMouseMove(e);
}
The startDragging method needs to create a toplevel window that can be moved around with the mouse, containing a facsimile of the tab we're dragging around. We'll display it as an owned window, so it is always on top, that has the exact same size as the tab control:
private void startDragging() {
draggingBounds = this.RectangleToScreen(new Rectangle(Point.Empty, this.Size));
draggingHost = createDraggingHost(draggingBounds);
draggingPos = Cursor.Position;
draggingHost.Show(this.FindForm());
}
The createDraggingHost needs to do the heavy lifting and create a window that looks just like the tab. A borderless form we'll move around with the mouse. We'll use the TransparencyKey property to make it look similar to the dragged TabPage with a tab sticking out at the top. And make it look the same by simply letting it display a screenshot of the tabpage:
private Form createDraggingHost(Rectangle bounds) {
var host = new Form() { FormBorderStyle = FormBorderStyle.None, ControlBox = false, AutoScaleMode = AutoScaleMode.None, Bounds = this.draggingBounds, StartPosition = FormStartPosition.Manual };
host.BackColor = host.TransparencyKey = Color.Fuchsia;
var tabRect = this.GetTabRect(this.SelectedIndex);
var tabImage = new Bitmap(bounds.Width, bounds.Height);
using (var gr = Graphics.FromImage(tabImage)) {
gr.CopyFromScreen(bounds.Location, Point.Empty, bounds.Size);
gr.FillRectangle(Brushes.Fuchsia, new Rectangle(0, 0, tabRect.Left, tabRect.Height));
gr.FillRectangle(Brushes.Fuchsia, new Rectangle(tabRect.Right, 0, bounds.Width - tabRect.Right, tabRect.Height));
}
host.Capture = true;
host.MouseCaptureChanged += host_MouseCaptureChanged;
host.MouseUp += host_MouseCaptureChanged;
host.MouseMove += host_MouseMove;
host.Paint += (s, pe) => pe.Graphics.DrawImage(tabImage, 0, 0);
host.Disposed += delegate { tabImage.Dispose(); };
return host;
}
Note the use of the Capture property, that's how we detect that the user released the mouse button or interrupted the operation by any other means. We'll use the MouseMove event to move the window around:
private void host_MouseMove(object sender, MouseEventArgs e) {
draggingHost.Location = new Point(draggingBounds.Left + Cursor.Position.X - draggingPos.X,
draggingBounds.Top + Cursor.Position.Y - draggingPos.Y);
}
And finally we need to handle the completion of the drag. We'll swap tabs, inserting the dragged tab at the mouse position and destroy the window:
private void host_MouseCaptureChanged(object sender, EventArgs e) {
if (draggingHost.Capture) return;
var pos = this.PointToClient(Cursor.Position);
for (int ix = 0; ix < this.TabCount; ++ix) {
if (this.GetTabRect(ix).Contains(pos)) {
if (ix != this.SelectedIndex) {
var page = this.SelectedTab;
this.TabPages.RemoveAt(this.SelectedIndex);
this.TabPages.Insert(ix, page);
this.SelectedIndex = ix;
}
break;
}
}
draggingHost.Dispose();
draggingHost = null;
}
Looks pretty good.
since you hasn't shared ManagedTabPage code, i used default TabPage control
changes are made in method OnDragOver
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
namespace Demo
{
public class MyTabControl : TabControl
{
public MyTabControl()
{
SizeMode = TabSizeMode.Fixed;
ItemSize = new Size(224, 20);
}
#region Overriden base methods
protected override void OnDragOver(DragEventArgs e)
{
if (DesignMode)
return;
if (PointedTabPage == null) return;
e.Effect = DragDropEffects.Move;
var dragTab = e.Data.GetData(typeof(TabPage)) as TabPage;
if (dragTab == null) return;
int dropIndex = TabPages.IndexOf(PointedTabPage);
int dragIndex = TabPages.IndexOf(dragTab);
if (dragIndex == dropIndex) return;
// change position of tab
TabPages.Remove(dragTab);
TabPages.Insert(dropIndex, dragTab);
SelectedTab = dragTab;
base.OnDragOver(e);
}
protected override void OnMouseDown(MouseEventArgs e)
{
if (DesignMode)
return;
switch (e.Button)
{
case MouseButtons.Left:
DoDragDrop(PointedTabPage, DragDropEffects.Move);
break;
case MouseButtons.Middle:
TabPages.Remove(PointedTabPage);
break;
}
}
#endregion
TabPage PointedTabPage
{
get
{
return TabPages.OfType<TabPage>()
.Where((p, tabPageIndex) => GetTabRect(tabPageIndex).Contains(PointToClient(Cursor.Position)))
.FirstOrDefault();
}
}
}
}

Refresh panel in c#

I'm working on some project ... and when I add a user there is an information about hobby with the advantages of support -add more- hobby to the same person .
I'm thinking about divided my info into several user control and locate these user control dynamically inside the panel .
and when press the -add more- link it's build a new controls (label , textbox ...) and resize the user control containing them .
it's work but the problem is when I press -add more- the user control containing it resize well . but the panel did not build again so the user control get above other user controls without rearrange .
this is simple code of user control with add more :
public partial class UserControl2 : UserControl
{
public UserControl2()
{
InitializeComponent();
}
private void UserControl2_Load(object sender, EventArgs e)
{
this.Size = new Size(this.Size.Width , sss.Size.Height * 3);
}
private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
this.Size = new Size(this.Size.Width, sss.Size.Height * 6);
}
}
and the panel code is to locate when press button1 :
private void button1_Click(object sender, EventArgs e)
{
UserControl1 x1 = new UserControl1();
UserControl2 x2 = new UserControl2();
UserControl3 x3 = new UserControl3();
x1.Location = new Point(panel1.AutoScrollPosition.X , panel1.AutoScrollPosition.Y);
x2.Location = new Point(panel1.AutoScrollPosition.X , panel1.AutoScrollPosition.Y + x1.Size.Height);
x3.Location = new Point(panel1.AutoScrollPosition.X, panel1.AutoScrollPosition.Y + x1.Size.Height + x2.Size.Height);
panel1.Controls.Add(x1);
panel1.Controls.Add(x2);
panel1.Controls.Add(x3);
}
You can't increase the size of a control without it overlapping if you aren't anchoring the controls and increasing the size of the window.
While the form designer may look like it flows nicely, everything is created with fixed locations and sizes. If you start increasing the size of a control without taking the other controls into account, it will be drawn over them.
You should look into either anchoring your controls and increasing the window size, within reason, or instead of changing the underlying size, add the controls inside the panel and the needed location and enable auto scrolling for the panel.
This is example code:
private void button1_Click(object sender, EventArgs e)
{
if (!panel1.AutoScroll) panel1.AutoScroll = true;
for (int i = 0; i < 3; i++)
{
Textbox txt = new TextBox() { Location = new Point(3, (panel1.Controls.Count * 25) + 3 };
panel1.Controls.Add(txt);
}
}
Each time you click the button it will add 3 new textbox to the panel. You can use a similar pattern to this to accomplish what you are looking for with your own control. It also makes sure the panel can scroll so the users can go down the list without resizing the panel or the main form.
Try:
check out this link:
private void button1_Click(object sender, EventArgs e)
{
panel1.Controls.Clear();
//Then add your existing code below
serControl1 x1 = new UserControl1();
UserControl2 x2 = new UserControl2();
UserControl3 x3 = new UserControl3();
x1.Location = new Point(panel1.AutoScrollPosition.X , panel1.AutoScrollPosition.Y);
x2.Location = new Point(panel1.AutoScrollPosition.X , panel1.AutoScrollPosition.Y + x1.Size.Height);
x3.Location = new Point(panel1.AutoScrollPosition.X, panel1.AutoScrollPosition.Y + x1.Size.Height + x2.Size.Height);
panel1.Controls.Add(x1);
panel1.Controls.Add(x2);
panel1.Controls.Add(x3);
}

Manage windows inside a panel with a 'Windows'-like menu

I've a panel.
I add WinForms inside it. The WinForms added have the TopLevel and Visible properties set to FALSE and TRUE.
I can do a panel.SetChildIndex(WinForm1,0) to bring WinForm1 to front.
What I've not managed to do is keep a track of the actual ChildIndex of the panel.
The idea is to have buttons that opens forms inside the panel, and that when the panel opens a new button is added in a Windows menu.
Something like when many files are open on a VS Project, you can go to Window menu and select one. Also, if you change the active page by clicking the page, the Window menu auto-updates and checks the actual active page.
I want to do this, but with a panel container. I've managed to get done everithing, but not the the Window menu auto-updates and checks the actual active page part.
Isn't there an event fired when BringToFront() or SetChildIndex(form, index) are called? Any event when I click another form that's inside the panel and it becomes the "active one"? Or some property of the panel that I can keep track of that changes when active form changes?
It is taken from here
When Control's ZOrder is chaged layout operation is always performed
in control's container control.
When I subscribed to container's Layout event and called
BringToFront() it showed me Control that changed its
ZOrder(LayoutEventArgs.AffectedControl) and changed property
(LayoutEventArgs.AffectedProperty).
Found that when a form inside a panel is closed, the Controls property of the panel gets reindexed, where the index zero is the form that gets the new focus. Now that I've a way to check the form that's in front when I close another one, windows administration in panels is done.
Going to put the source code, maybe it can help someone :)
Please note that I'm using a RadRibbonForm, a standard panel, and RadForms inside the panel. Rad's are from Telerik. Some things should change to make this work on standardWinForms, but the changes are minimal.
Also, I'm not using a menu that shows the forms, I'm using RadButtonElement's in a page of the ribbon menu instead.
AddRadFormWindow must be called to put a window and manage it automatically.
Example of adding a window:
AddRadFormWindow(typeof (MyRadForm))
Now, the source. It must be inside the code of the RadRibbonForm's class.
public static class ExtensionsRadForm
{
[DllImport("user32.dll")]
private static extern int ShowWindow(IntPtr hWnd, uint msg);
public static void Deminimize(this RadForm form)
{
if (form.WindowState == FormWindowState.Minimized)
ShowWindow(form.Handle, 9);
}
}
private void RefreshButtonsChecks(string windowName)
{
if (windowName != null)
{
principalPanel.Controls[windowName].BringToFront();
}
if (principalPanel.Controls.Count > 0)
{
if (principalPanel.Controls.Cast<RadForm>().Any(radForm => radForm.WindowState != FormWindowState.Minimized))
{
foreach (RadItem item in radRibbonBarGroupOpenWindows.Items)
{
var buttonBorder = ((RadButtonElement) item).BorderElement;
if (item.Name == panelPrincipal.Controls[0].Name + "Button")
{
buttonBorder.ForeColor = Color.LimeGreen;
buttonBorder.BottomColor = Color.LimeGreen;
buttonBorder.TopColor = Color.LimeGreen;
buttonBorder.LeftColor = Color.LimeGreen;
buttonBorder.RightColor = Color.LimeGreen;
principalPanel.Controls[0].Focus();
}
else
{
buttonBorder.ForeColor = Color.Transparent;
buttonBorder.BottomColor = Color.Transparent;
buttonBorder.TopColor = Color.Transparent;
buttonBorder.LeftColor = Color.Transparent;
buttonBorder.RightColor = Color.Transparent;
}
}
}
else
{
foreach (RadItem item in radRibbonBarGroupAbiertas.Items)
{
var buttonBorder = ((RadButtonElement)item).BorderElement;
buttonBorder.ForeColor = Color.Transparent;
buttonBorder.BottomColor = Color.Transparent;
buttonBorder.TopColor = Color.Transparent;
buttonBorder.LeftColor = Color.Transparent;
buttonBorder.RightColor = Color.Transparent;
}
}
}
}
private void PrincipalPanelLayout(object sender, LayoutEventArgs e)
{
RefreshButtonsChecks(null);
}
private void RadButtonElementCloseAllWindowsClick(object sender, EventArgs e)
{
int limitButtons = radRibbonBarGroupOpenWindows.Items.Count;
for (int index = 0; index < limitButtons; index++)
{
RadItem radItem = radRibbonBarGroupOpenWindows.Items[0];
radItem.Dispose();
}
int limitControls = principalPanel.Controls.Count;
for (int index = 0; index < limitControls; index++)
{
Control control = principalPanel.Controls[0];
control.Dispose();
}
Update();
GC.Collect();
}
private void AddRadFormWindow(Type windowToAdd)
{
if (!principalPanel.Controls.ContainsKey(windowToAdd.Name))
{
var window = (RadForm) Activator.CreateInstance(windowToAdd);
window.TopLevel = false;
window.Visible = true;
window.FormClosing += (method, args) =>
{
radRibbonBarGroupOpenWindows.Items[window.Name + "Button"].Dispose();
GC.Collect();
};
window.Enter += (method, args) => RefreshButtonsChecks(window.Name);
var closeMenuItem = new RadMenuItem("Close");
closeMenuItem.MouseDown += (method, args) =>
{
panelPrincipal.Controls[window.Name].Dispose();
radRibbonBarGroupOpenWindows.Items[window.Name + "Button"].Dispose();
};
var contextMenu = new RadContextMenu();
contextMenu.Items.Add(closeMenuItem);
var button = new RadButtonElement(window.Text) {Name = window.Name + "Button"};
button.MouseDown += (method, args) =>
{
switch (args.Button)
{
case MouseButtons.Left:
if (((RadForm) principalPanel.Controls[window.Name]).WindowState ==
FormWindowState.Minimized)
((RadForm) principalPanel.Controls[window.Name]).Deminimize();
principalPanel.Controls[window.Name].BringToFront();
principalPanel.Controls[window.Name].Focus();
break;
case MouseButtons.Right:
contextMenu.Show(MousePosition);
break;
}
};
radRibbonBarGroupOpenWindows.Items.Add(button);
principalPanel.Controls.Add(window);
principalPanel.Controls[window.Name].BringToFront();
principalPanel.Controls[window.Name].Focus();
}
principalPanel.Controls[windowToAdd.Name].BringToFront();
principalPanel.Controls[windowToAdd.Name].Focus();
Update();
GC.Collect();
}
public Constructor()
{
panelPrincipal.Layout += PanelPrincipalLayout;
}

Categories