I'm a little confused as to why this isn't working, since I had it working in a prototype and the only big difference I think is that I use a custom TabItem and UserControl instead of the default ones. I'm trying to get the usercontrol that appears to be centered in the tab window, but it seems to be aligned left.
You hand this method the usercontrol you want to use and it formats it and sticks it in the tabcontrol. In a test solution I did of this earlier, setting scroll's horizontal and vertical alignment to stretch fixed this, but it's not working in this case. Is there some other setting or something else somewhere that would override this?
public void CreateNewTab(UserControlGeneric new_user_control, string tab_header)
{
//TabItem tab = new TabItem();
TabItemIndexed tab = new TabItemIndexed();
//The scrollviewer is created/setup to make sure the usercontrol gets scroll bars if the window if ever made smaller than the usercontrol
ScrollViewer scroll = new ScrollViewer();
//How you programatically set a scrollviewer's height and width to be "Auto"
scroll.Height = Double.NaN;
scroll.Width = Double.NaN;
scroll.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
scroll.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
scroll.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
scroll.VerticalAlignment = System.Windows.VerticalAlignment.Stretch;
scroll.Content = new_user_control;
tab.Content = scroll;
tab.Header = tab_header;
//If there aren't any tabs, then hide the "No Workspaces Open" notice (Since we're adding a tab)
if (!tabControl_main.HasItems) label_no_workspaces_open.Visibility = System.Windows.Visibility.Hidden;
tabControl_main.Items.Add(tab);
tabControl_main.SelectedItem = tab;
}
Related
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);
}
Let me begin by saying that I have not done a lot of Windows Forms development -- if there is an obvious mistake that I may be making, please don't hesitate to mention it.
Steps to reproduce my issue:
Create a new C# Windows Forms Project using VS 2010 or VS 2012
Using the VS Form Designer, add three FlowLayoutPanel components to the form
Set each FlowLayoutPanel to have the same height as the form and approximately 1/3 the width of the form
Position each FlowLayoutPanel so that they do not overlap each other horizontally and collectively consume approximately the entire area of the Form.
The leftmost FlowLayoutPanel is configured to have an Anchor of Top, Bottom, Left
The middle FlowLayoutPanel is configured to have an Anchor of Top, Bottom
The rightmost FlowLayoutPanel is configured to have an Anchor of Top, Bottom, Right
Add an event for Form_Shown:
private void Form1_Shown(object sender, EventArgs e)
{
Panel p = new Panel();
p.BorderStyle = BorderStyle.FixedSingle;
p.Width = 200;
p.Height = 100;
Label label1 = new Label();
label1.BorderStyle = BorderStyle.FixedSingle;
label1.Text = "Hello";
label1.Anchor = AnchorStyles.Top;
Label label2 = new Label();
label2.BorderStyle = BorderStyle.FixedSingle;
label2.Text = "World!";
label2.Anchor = AnchorStyles.Bottom;
p.Controls.Add(label1);
p.Controls.Add(label2);
middleFlow.Controls.Add(p); // add to the center most FlowLayoutPanel on Form1
}
The result seems to be that label1 is placed on top of label2, despite label2 being added second. Moreover, the anchor values seem to be ignored (as label1 is covering label2 when I intend for them to be anchored to the top and bottom of the Panel component, respectively)
If I use the Dock property instead of the Anchor property, the behavior is as desired. Why does the Anchor property not work in this situation?
Also, is there a way to anchor components to other components? I notice as I increase the size of my Form at runtime, horizontal "gaps" between panels appear. Ideally, I would like the panels to grow together, preventing any gaps/whitespace between them horizontally?
Thanks in advance for any suggestions or tips.
I'm still starting to learn c# and winforms, so the following may not be optimal but it does what you required.
Handled the labels with Dock=Top. Note that the labels are switched so that label1 is on top of label2, i.e., registering label1 last pushes down the already registered label2.
The positioning of the three panels is done without anchors and docks with an event handler for resize. Setting the size of the form after that raises a resize event. Colored to see the components.
using System;
using System.Drawing;
using System.Windows.Forms;
public class ThreePanel : Form {
FlowLayoutPanel leftFlow;
FlowLayoutPanel middleFlow;
FlowLayoutPanel rightFlow;
public ThreePanel(){
leftFlow = new FlowLayoutPanel() {
BackColor = Color.Yellow
};
middleFlow = new FlowLayoutPanel() {
BackColor = Color.LightGreen
};
rightFlow = new FlowLayoutPanel() {
BackColor = Color.LightBlue
};
this.Controls.Add(rightFlow);
this.Controls.Add(middleFlow);
this.Controls.Add(leftFlow);
this.Load += (s,e)=>Form1_Shown(s,e);
this.Resize += (s,e)=>{
int w=this.Width/3;
leftFlow.Width=middleFlow.Width
=rightFlow.Width=w;
leftFlow.Height=middleFlow.Height
=rightFlow.Height=this.Height;
leftFlow.Location=new Point(0,0);
middleFlow.Location=new Point(w,0);
rightFlow.Location=new Point(2*w,0);
};
this.Size = new Size(750,450);
}
private void Form1_Shown(object sender, EventArgs e)
{
Panel p = new Panel() {
BorderStyle = BorderStyle.FixedSingle,
Width = 200,
Height = 100,
BackColor = Color.Fuchsia,
};
Label label1 = new Label() {
BorderStyle = BorderStyle.FixedSingle,
Text = "Hello",
Dock = DockStyle.Top
};
Label label2 = new Label() {
BorderStyle = BorderStyle.FixedSingle,
Text = "World!",
Dock = DockStyle.Top
};
p.Controls.Add(label2);
p.Controls.Add(label1);
// add to the center most FlowLayoutPanel on Form1
middleFlow.Controls.Add(p);
}
public static void Main()
{
Application.Run(new ThreePanel());
}
}
I would expect exactly the behaviour that you mentioned.
The Anchor property only tells the parent container that the label should be sticked
to the parent. In your case AnchorStyles.Top means stick the label to the top and leave it there if the parent moves or resizes.
You did not specify dimensions or positions for the labels, so both overlapp.
The z-order of the controls is created implicitly from the order when added to middleFlow.Controls. You can check this using VS forms designer. Select "Bring to Front" or "Send to Back" and watch how the x.designer.cs changes.
Why it is in reverse order is one of the little .net secrets. The workaround is to change the order. Sometimes it is easier to do it manually than in the designer.
I want to add a StatusStrip to a UserControl and resize this UserControl at runtime. Here is how I add the StatusStrip.
StatusStrip sb = new StatusStrip();
sb.BackColor = System.Drawing.SystemColors.ControlDark;
sb.Dock = DockStyle.Bottom;
sb.GripMargin = new Padding(2);
sb.SizingGrip = true;
sb.GripStyle = ToolStripGripStyle.Visible;
sb.LayoutStyle = ToolStripLayoutStyle.HorizontalStackWithOverflow;
this.Controls.Add(sb);
The StatusStrip is displayed at the bottom of the UserControl. However there is no SizingGrip (little Triangle) in the right bottom corner of the StatusStrip. Why not?
It's not showing up because a UserControl is not a sizable control at runtime. The StatusStrip, nay more specifically the sizing grip, was built to support the Form control.
Here is the code for ShowSizingGrip, a private property used during paint:
private bool ShowSizingGrip
{
get
{
if (this.SizingGrip && base.IsHandleCreated)
{
if (base.DesignMode)
{
return true;
}
HandleRef rootHWnd = WindowsFormsUtils.GetRootHWnd(this);
if (rootHWnd.Handle != IntPtr.Zero)
{
return !UnsafeNativeMethods.IsZoomed(rootHWnd);
}
}
return false;
}
}
at this point I can see two point of interest. First, HandleRef rootHWnd = WindowsFormsUtils.GetRootHWnd(this);, I can't test this class because it's internal, but there's a really good chance it's not going to return a window. However, even if it did, if said window was currently maximized, !UnsafeNativeMethods.IsZoomed(rootHWnd);, the sizing grip wouldn't show either.
My educated guess -- your window is maximized. I make that assumption because it appears Cody Gray was able to make it show up on a UserControl.
I have TableLayoutPanel for dynamic creation of controls with AutoScroll = true. It's work fine when I add new controls. But when I remove and all controls are visible, vertical scroll is visible.
Some screenshots here:
Expected/correct scroll visibility:
Incorrect visibility:
Any ideas?
Update:
Here is some code
tableLayoutPanel1.SuspendLayout();
tableLayoutPanel1.RowCount = 0;
tableLayoutPanel1.RowStyles.Clear();
tableLayoutPanel1.AutoScroll = true;
tableLayoutPanel1.Padding = new Padding(0, 0, SystemInformation.VerticalScrollBarWidth, 0);
foreach (var item in objects)
{
tableLayoutPanel1.RowCount++;
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.AutoSize));
tableLayoutPanel1.Controls.Add(CreateNewItem(item));
}
tableLayoutPanel1.RowCount++;
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.AutoSize));
tableLayoutPanel1.Controls.Add(CreateAddButton());
tableLayoutPanel1.ResumeLayout();
and code for deleting
tableLayoutPanel1.SuspendLayout();
tableLayoutPanel1.Controls.Remove(item);
tableLayoutPanel1.RowStyles.RemoveAt(0);
tableLayoutPanel1.RowCount--;
tableLayoutPanel1.ResumeLayout();
AutoSize is true, AutoSizeMode is GrowAndShrink
The problem concerns TableLayoutPanel scrolling.
You have to use a Panel for scrolling instead of TableLayoutPanel.
Here is an example to solve this problem (for vertical scrolling) :
Set your TableLayoutPanel properties as follow :
Dock = DockStyle.Top
AutoSize = true
AutoSizeMode = AutoSizeMode.GrowAndShrink
AutoScroll = false.
Put your TableLayoutPanel into a Panel with properties :
Dock = DockStyle.Fill
AutoScroll = true
AutoSize = false.
when you remove the dynamic controls, you need to remove the extra rows that was inserted during the addition and re-size the table layout panel height to smaller than scroll container height.
During the addition the table layout panel height would have increased, which handled by the scroll container; but when you remove the controls, the table layout panel height doesn't reduce it's height to fit the scroll container.
One way to do this is to give fixed height to the rows and set the table layout panel seize set to "Auto".
One of the easiest and funniest solution is to just disable and enable tableLayoutPanel1.AutoScroll
In your Deleting procedure code add at the end these codes :
tableLayoutPanel1.AutoScroll = False
tableLayoutPanel1.AutoScroll = True
I inserted tableLayoutPanel to XtraScrollableControl(Devexpress control). tableLayoutPanel.Dock set to Top and XtraScrollableControl.Dock to Fill. This solution did not solves this problem, but I got behavior that I need.
I counted the number of rows in my TableLayoutPanel to see how many would fit. Below the amount that fit I set AutoScroll = false for the add and delete methods. The scroll will appear for large sets and disappear on small sets.
if (tableLayoutPanel.RowCount < 15)
{
panel1.AutoScroll = false;
}
else
{
panel1.AutoScroll = true;
}
I had a TableLayoutPanel on a UserControl, docked in Fill mode, with all rows on the TableLayoutPanel set to AutoSize. This UserControl would then dynamically get put on a panel, again in Fill mode, to show it to the user when needed. I put the UserControl on AutoScroll, but that alone did not solve it.
In the end, I solved it by going over all controls in the TableLayoutPanel, storing the extremities, and baking that into a Size to put in my UserControl's AutoScrollMinSize:
private void AdjustPanelSize(ScrollableControl panel, TableLayoutPanel tableLayoutPanel)
{
int maxX = 0;
int maxY = 0;
foreach (Control c in tableLayoutPanel.Controls)
{
maxX = Math.Max(maxX, c.Location.X + c.Width);
maxY = Math.Max(maxY, c.Location.Y + c.Height);
}
panel.AutoScrollMinSize = new Size(maxX, maxY);
}
This worked, and it also has the advantage that it can be called if there would ever be controls dynamically added or removed from the TableLayoutPanel.
Is there any way to Use the Builtin ScrollBars that comes with each .Net ScrollableControl without setting the AutoScroll Property to Enable?
Here is the issue, even If I Enable, set to Visible and declare min and max values as well as the smallChange and LargeChange for the HorizontalScrollBar and VerticalScrollBar they show up in the borders of the Control but they are useless. When clicked the thumb doesn't moves and the Scroll Event of the control doesn't bring any usefull information when scroll is clicked ( OldValue and NewValue are both 0)
This is how I tried to set up the Scroll Bars Values:
HorizontalScroll.Enabled = true;
HorizontalScroll.Value = 80;
HorizontalScroll.Minimum = 0;
HorizontalScroll.Maximum = 300;
HorizontalScroll.SmallChange = 2;
HorizontalScroll.LargeChange = 4;
HorizontalScroll.Visible = true;
(And did the same thing to the Vertical Scroll)
Any ideas? or do I have to add to new ScrollBars by myself to my control?
Well I couldn't find a way to reuse the same ScrollBars integrated with each Net Scrollable Control. Finally I made my own Scrolls and very Important ... override the AutoScroll Property if it is a Control someone else is going to reuse.
public override bool AutoScroll
{
get { return false; }
set
{
if (value)
throw new Exception("Auto Scroll not supported in this control");
base.AutoScroll = false;
}
}