I have a FlowLayoutPanel and there are multiple controls on it. I only want to scroll in vertical direction. But when I set AutoScroll = true, I got both Vertical and Horizontal Scroll bars. How could I disable the horizontal scroll bar and only keep the vertical scroll bar working?
Set AutoScroll to true
Set WrapContents to false.
Make sure the size is wider than the
controls' width plus the width of a vertical scrollbar.
The horizontal scrollbar should disappear. If it doesn't, please provide some more information.
Set AutoScroll to true.
Set WrapContents to false.
Set Padding Right to 10.
It's work pretty fine for me.
Here is how I implement to have multiple labels on a FlowLayoutPanel with wrap text(WrapContents = true), verticalscrollbar only.
I have a flowLayoutPanel1 on a form
Set properties of form and flowLayoutPanel1 like below:
form:
AutoScroll = True
FormBorderStyle = Sizable(default)
flowLayoutPanel1:
Anchor = Top, Left, Right
AutoSize = True
FlowDirection = TopDown
WrapContents = true
Implement this code on form class for testing
int coorY = 0;
public Form2()
{
InitializeComponent();
for (int i = 0; i < 100; i++)
{
flowLayoutPanel1.Controls.Add(new Label
{
Location = new Point(0, coorY + 20),
Font = new Font("Segoe UI", 10f),
Text = "I have a FlowLayoutPanel and there are multiple controls on it. I only want to scroll in vertical",
Width = flowLayoutPanel1.Width,
AutoSize = true
});
coorY += 20;
}
}
Vertical scrollbar in action
Related
Can anyone help me to understand the usefulness of the Margin property?
Using the simple scenario below, I can't see how it's useful
SET UP
I created a simple app to test this:
Created a new WinForms app from the template
Opened Form1 in the designer
Added a 'Panel' (called Panel1) onto Form1 from the toolbox, with:
Dock = Fill;
Size.Width = 800px;
Size.Height = 450px`;
Added two child 'Panels' onto Panel1
Panel2 has Dock = Left
Panel3 has Dock = Right
Both Panel2 and Panel3 have Size.Width = 400px, Size.Height = 450px (so Panel2 and Panel3 effectively split Panel1 into 2 down the middle)
WHY THE PADDING PROPERTY MAKES SENSE TO ME:
The usefulness of Padding is obvious in the designer - it enforces space between the border of the parent (Panel1) and its contents (Panel2 and Panel3)).
So if I set Panel1.Padding.All = 10, then the Size.Height of both Panel2 and Panel3 is forced to decrease (by 20px) to 430px.
Their Size.Width stays the same (they just become overlapped).
Winforms then prevents the Size.Height of Panel2/Panel3 from being increased above 430px, as this would encroach into the padding space of Panel1.
This all makes sense to me
WHY THE MARGIN PROPERTY DOES NOT MAKE SENSE TO ME
Margin is the space around the border of an element - it keeps other elements from getting too close to the element you're setting the Margin on.
So I thought that if I set Margin.Right (on Panel2) to 10px, this would force the Size.Width of Panel3 to decrease (so that it wasn't encroaching on the margin of Panel2).
Instead, setting this right margin appears to have no visible impact on the form?
The Margin property is primarily used by the visual designer and reflected with "snaplines" when positioning controls on the design surface.
See this walkthrough from Microsoft.
One way to think about it (generally) is that Margin is something that happens outside the control whereas Padding is something that happens inside. Also, the "total" effect can be the result of the parent's padding added to the margin of the child control.
The MainForm has padding of 25 (shown in blue) and contains a FlowLayoutPanel set to Dock.Fill. To avoid confusion, the padding and margin of the flow layout panel is set to 0.
The 6 child controls of the flow layout panel set their own left-top margin to 10 and bottom margin to 40. At the top left and the bottom of each child the BackColor of LightSalmon shows through. There is a total of 50 from the bottom of one child to the top of the next one below. Each child control also sets its padding value to 15 which will apply on all four sides of the buttons it contains.
The padding and margin of Button are also set to 0. The the button is auto-sized and centered because it is anchored on all sides.
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
// Main form Padding in light blue
BackColor = Color.LightSkyBlue;
Padding = new Padding(25);
flowLayoutPanel.BackColor = Color.LightSalmon;
// Set these to 0 and let the individual controls
// manage the padding and margins.
flowLayoutPanel.Margin = new Padding(all: 0);
flowLayoutPanel.Padding = new Padding(all: 0);
for (int i = 1; i <= 6; i++)
{
var panel = new TableLayoutPanel
{
Name = $"panel{i}",
Size = new Size(200, 100),
// Margin 'outside' the panel will show in Light Salmon.
// This will space the panels inside the FlowLayoutPanel
Margin = new Padding(left: 10, top: 10, right: 0, bottom: 40),
// The button inside this panel will have Padding around it.
Padding = new Padding(all: 15),
BackColor = Color.LightGreen,
BackgroundImage = new Bitmap(
Path.Combine(
AppDomain.CurrentDomain.BaseDirectory,
"Images",
"back-image.png"
)),
BackgroundImageLayout = ImageLayout.Stretch,
};
// Add button to internal panel
var button = new Button
{
Name = $"button{i}",
Text = $"Button {(char)(64 + i)}",
BackColor = Color.DarkSeaGreen,
ForeColor = Color.WhiteSmoke,
// By anchoring the button, it will autosize
// respecting the Padding of its parent.
Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom,
Margin = new Padding(all: 0),
Padding = new Padding(all: 0),
};
panel.Controls.Add(button);
flowLayoutPanel.Controls.Add(panel);
}
}
}
I need a label to appear in the middle bottom (like 30px above the bottom line) of a panel, that also auto sizes to wrap the text depending on how long the text is.
So far I can only have the label auto size to wrap the text and have it docked at the bottom. But it is at bottom left and not middle.
As is on this example Long Text Image and Image of short text I'd like to center
(sorry the text is not clear but its at the bottom in white)
I was able to achieve the auto size using the ClientSizeChanged event as below.
private void Panel1_ClientSizeChanged(object sender, EventArgs e)
{
label8.MaximumSize = new Size((sender as Control).ClientSize.Width - label8.Left, 10000);
}
How do I have the text at the middle? It should be able to maintain the bottom middle (dock) position as I resize the panel.
Try following:
To your panel add TableLayoutPanel with following Properties:
tableLayoutPanel1.AutoSize = true; // This can be set at the end if you use designer
tableLayoutPanel1.ColumnCount = 1;
tableLayoutPanel1.RowCount = 1;
tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Bottom;
panel1.Controls.Add(tableLayoutPanel1); // add TableLayoutPanel to your panel
tableLayoutPanel1.Controls.Add(label1, 0, 0); // Add your label to TableLayout
And set properties on Label:
label1.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
label1.AutoSize = true;
label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
Now you can set
tableLayoutPanel1.AutoSize = true;
It is kind of tricky but should give you what you need.
I'm currently trying to create a visual component to have scrolling text (left to right and right to left) - pretty much an html marquee.
I have a grid divided in several columns & rows, and I want to place my component inside one of the grid slots.
The grid (named UIGrid) is generated like this :
for (int i = 0; i < xDivisions; i++)
{
ColumnDefinition newColumn = new ColumnDefinition();
UIGrid.ColumnDefinitions.Add(newColumn);
}
for (int i = 0; i < yDivisions; i++)
{
RowDefinition newRow = new RowDefinition();
UIGrid.RowDefinitions.Add(newRow);
}
The component I'm adding is just a border with a textblock as a child. I place the border inside the Grid like this :
border = new Border();
Grid.SetColumn(border, xPosition);
Grid.SetRow(border, yPosition);
textBlock = new TextBlock();
border.Child = textBlock;
textBlock.Text = "Scrolling text from left to right";
UIGrid.Children.Add(border);
I'm using a timer to increment the textblock margin, here's the timer callback simplified body :
textBlock.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
double textWidth = textBlock.DesiredSize.Width;
double visibleWidth = componentBase.ActualWidth;
double targetMargin = textWidth < visibleWidth ? visibleWidth : textWidth;
if (margin.Left == targetMargin)
{
margin.Left = -textWidth;
} else
{
margin.Left++;
}
When the text slides from left to right, it behaves nicely :
https://s10.postimg.org/p0nt7vl09/text_good.png
Text "leaving" the grid slot is hidden.
However, when I set the textblock's margin as negative so it may come back inside the viewable area from the left, the text is visible even though it's outside its allocated slot :
https://s10.postimg.org/pownqtjq1/text_bad.png
I've tried using padding instead, but I can't set a negative padding. I've tried a few other things, but I feel like I've encountered a roadblock.
What could I do to get a nicely scrolling text ?
If you want nicely scrolling text ListView might be a better option. It is dynamic and you can bind it to your object. It would take a lot of this guess work out.
Ed Plunkett led me in the right direction with the Clip property. The idea is to do this :
border.Clip = new RectangleGeometry
{
Rect = new Rect(0, 0, border.ActualWidth, border.ActualHeight)
};
Of course, that doesn't work if the border hasn't been rendered yet (and of course it isn't when my code is running). You can force the measurement to take place using 'Measure' as I did to measure the text length in pixels, but it behaved strangely on my border. I wouldn't get the correct size at all.
In the end, I simply subscribed to the border's SizeChanged event :
border.SizeChanged += OnSizeComputed;
When that event is fired, I create the RectangleGeometry using ActualWidth & ActualHeight.
I have a Canvas named mainCanvas and I'm programatically adding a ScrollViewer and a StackPanel to it in order of
...mainCanvas
......scrollView
.........pnl
............ (more stacked controls)
I'm attempting to get my StackPanel to auto size to the mainCanvas size and allow scrolling when it's too large. Code so far is below
mainCanvas.Children.Clear();
// Create the container
ScrollViewer scrollView = new ScrollViewer();
scrollView.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
scrollView.CanContentScroll = true;
scrollView.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
scrollView.VerticalAlignment = System.Windows.VerticalAlignment.Stretch;
StackPanel pnl = new StackPanel();
//pnl.Height = 500; //Works and allows scrolling but doesn't resize
pnl.Height = Double.NaN; //(Double.NaN is Auto) Doesn't Work - StackPanel overflows parent window
pnl.VerticalAlignment = System.Windows.VerticalAlignment.Stretch;
pnl.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
scrollView.Content = pnl;
// Add the ScrollView and StackPanel to Parent Window
mainCanvas.Children.Add(scrollView);
Unfortunately, the StackPanel doesn't fit to the parent and doesn't autosize.
mainCanvas already exists in XAML with settings:
Width= "Auto"
Height= "Auto"
HorizontalAlignment = "Stretch"
VerticalAlignment = "Stretch"
I can get things semi-working by using pnl.Height = 500; which shows me the scrollbar does work if the Stackpanel height is restricted. But this is just manually fitting the height to the full screen size and so doesn't autosize when resizing the app.
I hoped setting pnl.Height = Double.NaN; to auto and V/H adjustment to Stretch would work but the StackPanel still overlaps all controls to it's maximum size.
Can anyone point me in the right direction to get my StackPanel to fit the parent mainCanvas and autosize when I resize either the parent and/or the main app window with scrolling?
Thank you
I believe Canvas is for absolute positioning only. Using a Grid as your panel instead would probably give you the desired result.
The StackPanel won't stretch to fill its container, as you noticed. But you can bind its MinWidth and MinHeight properties to its container's width/height.
// give the canvas a name, so you can bind to it
mainCanvas.Name = "canvas";
// create the binding for the Canvas's "ActualHeight" property
var binding = new System.Windows.Data.Binding();
binding.ElementName = "canvas";
binding.Path = new PropertyPath("ActualHeight");
// assign the binding to the StackPanel's "MinHeight" dependency property
sp.SetBinding(StackPanel.MinHeightProperty, binding);
I'm trying to create an application that looks similar to the Windows Vista sidebar. There's an API that allows docking toolbars on the screen (AppBar), but it's not exactly what I'm looking for.
How can I attach a Form to the desktop and dock it to the side of the screen, but without preventing other windows from overlapping it?
With all the following options you get a Sidebar look-a-like (the code below is for a WPF Window):
//width of the sidebar
Width = 300;
//height (remember to add a reference to the System.Windows.Forms dll)
Height = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Height;
//no window style means no border
WindowStyle = WindowStyle.None;
//not resizable
ResizeMode = ResizeMode.NoResize;
//allow a transparent sidebar
AllowsTransparency = true;
//change the color
Background = new SolidColorBrush(Colors.CadetBlue);
//set the opacity (how much transparent)
Opacity = 0.5d;
//offset from the top
Top = 0;
//offset from the left (calculated so it shows on the right side)
Left = SystemParameters.PrimaryScreenWidth - (double)GetValue(WidthProperty);
//set it the topmost window
Topmost = true;
//hide the icon from the taskbar
ShowInTaskbar = false;
Hope this helps!
Update:
Here's a similar solution for when you're using WindowsForms, altough with WPF you have much more possibilities! The differences are minor, everything explains itself. The last line I added hides the window taskbar-icon. Do not place the code in the constructor of the Form but in the Load-event, otherwise the Location will be wrong. In WPF this doesn't matter.
Width = 300;
Height = Screen.PrimaryScreen.Bounds.Height;
FormBorderStyle = FormBorderStyle.None;
BackColor = Color.CadetBlue;
Opacity = 0.5d;
Location = new Point(Screen.PrimaryScreen.WorkingArea.Width - Width, 0);
TopMost = true;
ShowInTaskbar = false;