At runtime I am adding controls to a control that inherits from TableLayoutPanel. Controls are added one at a time, based on user interaction, not in a loop.
Here's the setup of my control that inherits from the TLP:
this.RowCount = 0;
this.RowStyles.Clear();
this.Dock = DockStyle.Fill;
this.VerticalScroll.Enabled = true;
this.HorizontalScroll.Enabled = false;
this.AutoScroll = true
And I'm adding user-controls to the bottom of the panel like this:
var uc = new FooControl();
this.Controls.Add(uc);
this.SetRow(uc, this.Controls.Count - 1);
this.SetColumn(uc, 0);
I would like to scroll that row/control into view.
How is that done?
To scroll a control into view in a ScrollableControl like TableLayoutPanel, you can use ScrollControlIntoView method. For example:
this.ScrollControlIntoView(uc);
Note: It doesn't select the control.
Also If you call Select method of a control, it will be selected (if selectable) and also its scrollable parent will be scrolled to bring the selected child control into view. For example:
uc.Select();
You can do that by setting the VerticalScroll of the Panel but I think it would be better to use ScrollControlIntoView instead.
private void panel1_ControlAdded(object sender, ControlEventArgs e)
{
panel1.ScrollControlIntoView(e.Control);
}
or
panel.VerticalScroll.Value = panel.VerticalScroll.Maximum
Related
Hey so I am attempting to create a form in which there are two buttons (acting as tabs) on the side in which when one is pressed specific controls are shown and when the other is pressed, another set are shown.
I have gotten this to work very well however I have run into an issue when about to create my second set of controls, how am I going to draw them (in designer) ontop of current controls (it's fine during runtime)? So my question is, how can I make this work. Current (possibly) important code:
private void CheatButton_Click(object sender, EventArgs e)
{
CheatControls(true);
ColorControls(false);
CheatButton.Normalcolor = Color.FromArgb(51, 51, 51);
ColorButton.Normalcolor = Color.FromArgb(61, 61, 61);
}
private void ColorButton_Click(object sender, EventArgs e)
{
CheatControls(false);
ColorControls(true);
CheatButton.Normalcolor = Color.FromArgb(61, 61, 61);
ColorButton.Normalcolor = Color.FromArgb(51, 51, 51);
}
private void CheatControls(bool b)
{
TriggerSwitch.Visible = b;
TriggerLabel.Visible = b;
BhopSwitch.Visible = b;
BhopLabel.Visible = b;
GlowSwitch.Visible = b;
GlowLabel.Visible = b;
RecoilSwitch.Visible = b;
RecoilLabel.Visible = b;
}
private void ColorControls(bool c)
{
}
My windows form application with an understandable graphic
Put all your cheat controls in a custom UserControl and all your color controls in a different custom UserControl. You can edit the different control sets easily in the designer, and in your code you can hide/show them more easily by setting the appropriate UserControl's visibility rather than setting the visibility of a bunch of controls individually. Here's an (admittedly old) example of creating a UserControl: msdn.microsoft.com/en-us/library/aa302342.aspx
When you create a UserControl in Visual Studio, you can add the controls to it using the designer. In your form with the tab buttons, you would add instances of the two UserControls that you created. Since UserControl derives from Control, it has a Visible property. So, in your CheatControls(bool b) method, your implementation would be simplified to something like _myCheatControls.Visible = b;. I haven't watched the whole thing, but this video might help, too: youtube.com/watch?v=l5L_q_jI494
You can use
XanderUI
Simply add a SuperButton(acts as a tab button) and when its clicked show a panel with your controls in it
EG -
private void ShowControlSet(int ControlSet)
{
panel1.visible = false;
panel2.visible = false;
if (ControlSet == 1) panel1.visible = true;
if (ControlSet == 2) panel2.visible = true;
}
// To show a panel use
ShowControlSet(1);
Your also able to use BringToFront() instead of making each panel invisible / visible but you need to anchor or dock the panels correctly
asides the visibility, what you can do is get the position of the buttons and st them when hiding and showing the other buttons
just set the top and left positions, ensuring the buttons are the same size.
I have a simple user control like this:
And yes, it has nothing inside, the controls will be dynamically added inside the user control using below on control load event:
List<Control> controlsNeed = getUserControls();
foreach(Control c in controlsNeed)
{
this.Controls.Add(c);
}
The controls loaded correctly, but if there're many controls, there won't be enough space and scroll bars will be needed.
The problem is, the scroll bar isn't added to the control despite setting the below:
Setting AutoScroll to true in the user control
Try setting AutoSize to false and true
What settings / code should be added to add scrollbar to the control?
List<Control> controlsNeed = getUserControls();
int PaddingTop = 10;
foreach (Control c in controlsNeed)
{
this.Controls.Add(c);
c.Location = new Point(0, c.Height + PaddingTop);
}
Or you can inherit the Panle control to your user control that will work like a panel control
public partial class MyControl : Panel
{
}
I think adding AutoScrollMinSize to user control should solve the problem
public MyUserControl()
{
InitializeComponent();
AutoScrollMinSize=new Size(0,1);
AutoScroll = true;
}
I have a flowlayoutpanel in my winform in which the images are added dynamically. I want the vertical scroll bar to always be at the bottom showing the last image added. How can i do that?
I have
AutoScroll = true
FLow Direction = Top Down
Wrap Content = False
Scrollable container controls, like FlowLayoutPanel, automatically keep the control with the focus in view. But PictureBox is special, it cannot receive the focus. So you have to help by explicitly asking the FLP to make the added control visible, use its ScrollControlIntoView() method. Like this:
var pic = new PictureBox();
//...
flowLayoutPanel1.Controls.Add(pic);
flowLayoutPanel1.ScrollControlIntoView(pic);
With the strong advantage that this works for any layout setting you applied to the FLP. You can also tinker with the AutoScrollPosition property, but it is harder to get that right:
flowLayoutPanel1.AutoScrollPosition = new Point(
pic.Right - flowLayoutPanel1.AutoScrollPosition.X,
pic.Bottom - flowLayoutPanel1.AutoScrollPosition.Y);
Try this:
scrollBar.Value=scrollBar.Maximum;
here scrollBar is your ScrollBar control in winform.
For more detail, check this.
Here is a way to force the last control into view.
flowLayoutPanel.ScrollControlIntoView(Control_To_Add); // Control_To_Add is the control we want to scroll to
Button TempButton = new Button();
TempButton.Width = _Panel.ClientRectangle.Width - 6; // Make the last control in the _Panel
flowLayoutPanel.Controls.Add(TempButton); // We add this TempButton so we can scroll to the bottom of the _Panel.Controls
flowLayoutPanel.ScrollControlIntoView(b); // We scroll to TempButton at the bottom of the _Panel.Controls
flowLayoutPanel.Controls.Remove(b); // We remove TempButton
b.Dispose(); // clean up
Forcing A FlowLayoutPanel to scroll to and display all of a control.
Code Correction:
flowLayoutPanel.ScrollControlIntoView(Control_To_Add); // Control_To_Add is the control we want to scroll to
Button TempButton = new Button();
TempButton.Width = _Panel.ClientRectangle.Width - 6; // Make the last control in the _Panel
flowLayoutPanel.Controls.Add(TempButton); // We add this TempButton so we can scroll to the bottom of the _Panel.Controls
flowLayoutPanel.ScrollControlIntoView(TempButton); // We scroll to TempButton at the bottom of the _Panel.Controls
flowLayoutPanel.Controls.Remove(TempButton); // We remove TempButton
b.Dispose(); // clean up
This is the correct way:
MyControl uct = new MyControl();
uct.Parent = flowLayoutPanel;
this.ActiveControl = uct;
if (flowLayoutPanel.VerticalScroll.Visible)
{
flowLayoutPanel.ScrollControlIntoView(uct);
}
I have a form with three panels.
I want the top two to be a fixed height, and bottom one to fill the rest of the space.
The dialog is resizable, so all should change width on resixze, and bottom one should change height.
This is important, the user must be able to stretch the form, as well as the program through code.
If I set a panel to visible = false, I want the form height to shrink so the others stay the same height.
If I set a panel to visible = true, I want the form height to grow by the height of the panel.
I will control the hiding/showing of the panels with buttons. The idea is I show certain panels for "advanced" mode in my form, and hide them for "simple" mode. I cannot have a bunch of blank space if I hide a panel, and I want the form to shrink a bunch for simple mode.
I tried doing this with panels docked to top, but a form resize by the user will not change a panel height. So that is the main trick I am asking for help on.
Anyone in this kind of situation can use the below styling:
Use 2-3 Panel to Group different Controls and place them in a single parent control say a GroupBox.
Make all the child panels Dock to the same side say "Top".
if any of the panel is jumping over another due to similar docking. In Visual Studio, go to menu View > Other Windows > Document Outline and Set the display order. (https://msdn.microsoft.com/en-us/library/46xf4h0w%28v=vs.80%29.aspx)
Set the Panel property as follows:
AutoSize: true
AutoSizeMode: GrowAndShrink
Once the panel is not visible, other panel will take away the empty space.
Hope this helps!!!
the other posts are close, there is a detail missing that I included in the solution I came up with. Its a flag to tell if the sized event was caused by a user form resize, or the program doing it when a panel is shown or hidden.
For this solution, make a form with 4 panels.
Set dock to top for all panels. Do not set any autosizing for panels or form.
Also make two buttons and place on top panel, or any panel that you will not be hiding.
The code below shows how to handle the resized event, and the showing hiding buttons.
I made them hide/show panel 2, but the code should work for any panel.
namespace ProgTesting {
public partial class Form5 : Form {
private bool doNothing = false;
public Form5() {
InitializeComponent();
cmdAdvanced.Visible = false;
}
private void cmdSimple_Click(object sender, EventArgs e) {
if (panel2.Visible) {
panel2.Visible = false;
doNothing = true;
this.MinimumSize = new Size(this.Width, this.Height - panel2.Height);
this.Height = this.Height - panel2.Height;
doNothing = false;
cmdSimple.Visible = false;
cmdAdvanced.Visible = true;
}
}
private void cmdAdvanced_Click(object sender, EventArgs e) {
if (!panel2.Visible) {
panel2.Visible = true;
doNothing = true;
this.Height = this.Height + panel2.Height;
this.MinimumSize = new Size(this.Width, this.Height);
doNothing = false;
cmdAdvanced.Visible = false;
cmdSimple.Visible = true;
}
}
private void Form5_SizeChanged(object sender, EventArgs e) {
if (!doNothing)
if (panel2.Visible)
panel3.Height = this.ClientSize.Height - panel1.Height - panel2.Height - panel4.Height;
else
panel3.Height = this.ClientSize.Height - panel1.Height - panel4.Height;
}
}
}
You do have to manage the heights going on, which is a pain but gives you control. Some shots of it working:
It sounds like what you are looking for is an Expander. Essentially a control that consists of a header and a content area, where clicking on the header toggles the content area between visible and collapsed.
I'm not 100% certain if an Expander control will automatically adjust the height of a form when it expands/collapses though. You may need to hook up an event handler to the Expander to manually adjust the height of your form when the Expander collapses.
Try looking at the Stack Overflow Question Add an expander (collapse/expand) to a Panel WinForm. There are a number of links from that question about implementing an Expander in Windows Forms, including some that provide full source code.
Update:
I've knocked up a quick demo that will accomplish what you want, in a very primitive way, not using any of the various Expander controls out there. I think that while you will find the Expanders useful, I doubt they will adjust the size of the container they are inside, unless you write some adjustment code like I have below.
Create a form that looks like this:
The two text boxes are anchored Left, Top, Right.
The toggle button is anchored Left, Top, named btnTogglePanel.
The magenta panel is anchored Left, Top, Right, Bottom, named pnlToggled.
The bottom button is anchored Right, Bottom.
Then in the code behind for the form:
public partial class ToggleableExpanderForm : Form
{
public ToggleableExpanderForm()
{
InitializeComponent();
SizeChanged += (s, args) =>
{
if (_LastSize.HasValue)
{
var diff = Size - _LastSize.Value;
if (_LastHeight.HasValue
&& !IgnoreNextResizeForLastHeightAdjustment)
{
_LastHeight += diff.Height;
}
}
_LastSize = Size;
};
}
private Size? _LastSize;
private bool IgnoreNextResizeForLastHeightAdjustment = true;
private int? _LastHeight;
private void btnTogglePanel_Click(object sender, EventArgs e)
{
var newVisibility = !pnlToggled.Visible;
int heightAdjustment = 0;
if (newVisibility)
{
if (_LastHeight.HasValue)
{
heightAdjustment = _LastHeight.Value;
_LastHeight = null;
}
}
else
{
_LastHeight = pnlToggled.Height;
heightAdjustment = -pnlToggled.Height;
}
pnlToggled.Visible = newVisibility;
IgnoreNextResizeForLastHeightAdjustment = true;
Height += heightAdjustment;
}
}
Essentially you adjust the height of the form manually when the toggle button is clicked, based on whether or not the panel is hiding/showing. You also need to take into account of what will happen when the user resizes the form when the panel is invisible, which is where the cruft around listening to the SizeChanged event comes in. You need the answer to "how MUCH has the size changed" and then you adjust your previously stored panel height as appropriate.
I don't imagine the above code is perfect, and I haven't tested it in every use case, but it gets the basic job done.
One way to go about it is to use a TableLayoutPanel for the top two panels.
The steps below will give you the resizing desired when the user resizes the form.
Start by created a TableLayoutPanel (TLP) and shrink it down from the default 2 columns, 2 rows to just 2 columns, 1 row.
Anchor it to Top, Left, and Right
Now size the TLP to fit your top two panels and place each panel in a cell of the TLP.
Anchor these two panels to all sides.
Position the 3rd panel (Panel3) below the TLP to your liking and anchor it to all sides.
To handle the hiding of Panel3 some logic will need to be added to the appropriate button_Click event. Determine what size you would like the "minimized" height to be and then just store the form size when Panel3 is visible and restore the height when it's clicked again. It should look something like this.
private void button1_Click(object sender, EventArgs e)
{
if (panel3.Visible)
{
// make invisible
panel3.Visible = false;
// storedHeight is a private member of the Form
storedHeight = Form1.ActiveForm.Height;
Form1.ActiveForm.Height = minimumHeight; // Set to predetermined minimum height
}
else
{
// make visible
panel3.Visible = true;
Form1.ActiveForm.Height = storedHeight;
}
}
Now when you hide Panel3 the form will shrink to the size of the TLP, then grow again when Panel3 is visible. Also the top panels will expand in width, but not height. You will need to change the MinSize properties of the form and its value will have to be dynamically adjusted depending on whether Panel3 is visible or not.
I have a panel of labels, buttons and image that I wish to put into a flow layout panel.
As seen in some tutorial, I understand that it is possible to auto align new and additional buttons into a flow layout panel.
what I would like to ask is that is it possible to put a panel WITHIN a flow layout panel and call multiple instances of the same panel to appear within the flow layout panel.
My panel code would be
this.panelNotification.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.panelNotification.Controls.Add(this.button1);
this.panelNotification.Controls.Add(this.lblImage);
this.panelNotification.Controls.Add(this.lblName);
this.panelNotification.Controls.Add(this.lblLinkName);
this.panelNotification.Controls.Add(this.lblLinkLocation);
this.panelNotification.Controls.Add(this.lblLocation);
this.panelNotification.Location = new System.Drawing.Point(3, 3);
this.panelNotification.Name = "panelNotification";
this.panelNotification.Size = new System.Drawing.Size(506, 100);
this.panelNotification.TabIndex = 17;
So is it possible to include the whole panel into a flow layout panel? if yes, how do i do it. thank you.
Yes, you can put a Panel into a FlowLayoutoutPanel.
No, you can't put a control several times into a FlowLayoutoutPanel (in fact you can, but it is only displayed once).
But what you could do is writing some kind of Factory-Method that creates a new Panel with new Buttons/Labels/other Controls etc. every time you call it, and add these new instances to your FlowLayoutpanel. Something like this:
public class Form1
{
private Panel CreateNotificationPanel()
{
var p = new Panel { BackColor = Color.Red };
p.Controls.Add(new Button { Text = "Test" });
return p;
}
private void Form1_Load(System.Object sender, System.EventArgs e)
{
var flp = new FlowLayoutPanel { Dock = DockStyle.Fill };
flp.Controls.Add(CreateNotificationPanel());
flp.Controls.Add(CreateNotificationPanel());
flp.Controls.Add(CreateNotificationPanel());
this.Controls.Add(flp);
}
public Form1() { Load += Form1_Load; }
}
Another (and problably better) approach would be to create a UserControl that contains your Buttons/Labels/etc. instead of using a panel and adding all controls manually. Just create with the Designer and add new instances of the UserControl to the FlowLayoutPanel.