Making control docking and scrollbars play nicely - c#

I've got a panel which will sometimes need more vertical screen space than naturally fits, so it needs to be able to vertically scroll. So, it's all set to AutoScroll.
The controls are contained within a TableLayoutPanel and set to dock, so they should resize their width to match. Yet, when the control triggers the scrollbar, it always ends up creating a horizontal scrollbar, even though there's no minimum width constraint on the control that's being violated. It's creating the horizontal scrollbar based on the previous width rather than respecting the dock command and redrawing the control to fit the new width.
Is there a better way round this?

Try this:
Outer panel:{AutoScroll=true, Dock=Fill}
Inner panel:{Dock=Top,Width=customwidth}

Yes, that's an inevitable consequence from the way layout is calculated. Getting rid of the horizontal scrollbar would require multiple passes through the calculation but .NET only makes one pass. For a good reason, layout can be bi-stable, flipping back and forth between two states endlessly.
I don't really understand how a TableLayoutPanel would be useful here or what makes it grow. In general, just don't dock it, give it the size you want to fill the panel. Something like this perhaps:
bool resizingTlp;
private void tableLayoutPanel1_Resize(object sender, EventArgs e) {
if (resizingTlp) return;
resizingTlp = true;
if (tableLayoutPanel1.Height <= panel1.ClientSize.Height) tableLayoutPanel1.Width panel1.ClientSize.Width;
else tableLayoutPanel1.Width = panel1.ClientSize.Width - SystemInformation.VerticalScrollBarWidth;
resizingTlp = false;
}

Related

How to resize DataGridView's scrollbar?

I know there are answers which involves adding an external scrollbar control to the DGV, and disabling its original scrollbars.
While this approach works, it can be very hard to solve all use-cases around DpiChange events plus I wish the scrollbar to not visible during displaying smaller amount of data then DGV's height.
Main problem:
This DGV (at 100% scaled display):
becomes this when moved to another display with 250% scale:
I managed to enlarge it with this:
VScrollBar? scrollbar = dataGridView1.Controls.OfType<VScrollBar>().FirstOrDefault();
if (scrollbar != null) scrollbar.MinimumSize = new() { Width = 40; }
However, my problem is that its position (i.e. its left property) is wrong, and it goes out of its parent (and also mask parent's border):
How can I ask the DGV's scrollbar to scale properly without adding more scrollbars to it?

How would I stop panels from erasing rectangles I've drawn when I scroll down?

I'm coding a charting control in C# for the .net framework. I basically have a split panel where I write the names on one side and draw rectangles on the other for the actual graph portion of the control. However, I've realized that every time I scroll down, it erases the part of the rectangles that go out of the panel's view. How do I prevent this?
Side question, how do I make the scroll bar for the second panel work for both. I'm fairly new to some of this stuff so I apologize if anything here is fairly elementary or already answered. Thanks for your time!
Funnily enough, the answer to your question about scrolling will actually solve the drawing problem. The solution is to add a 3rd panel with AutoScroll set to true. Then place your existing two panels inside that one. Don't dock them, but rather set them to their full size. The parent panel's scrollbar will scroll both and instruct them to repaint as needed.
Also see this answer. It's better to derive your own class from Panel and draw on that.
For future reference, when you are drawing directly on an AutoScroll panel, use TranslateTransform to account for the scrolling. This solves the drawing issue for me:
private void Panel1_Paint(object sender, PaintEventArgs e) {
e.Graphics.TranslateTransform(panel1.AutoScrollPosition.X, panel1.AutoScrollPosition.Y);
// draw something...
}

How to deal with controls and form's stretching in WinForms

Suppose that I have the following form in Designer:
I want to give users the ability to stretch this form as they want and all controls should be located like in the picture, no matter how user changed the size of this form, so they should take the same amount of space and stick to the same controls and borders.
How can I do it in WinForms? I know that there are such things like Docks etc, but I didn't find the correct way to use them in this situation.
You want the Anchor property in this case, not Dock. Anchoring means that a control will always keep the same distance to certain sides (top, left, right, and/or bottom) even if it means that the size must be changed; docking OTOH does not care about margins, it just fills up all available space on one or all sides.
Here's what you might want to do:
Anchor the two image buttons to the top and right.
Anchor the OK button to the right and bottom (I guess).
Anchor the large ListBox to all sides.
Just To Add some notes on good answer of stakx
For Controls Like ListBox that have a limit to their height, setting anchor is not enough and you should set IntegralHeight of them to false.
I reccomend to set MinimumSize of Form to prevent a user from sizing a window to an undesirable size.In your case Set it to a minimum acceptable size to prevent ugly small form with an unusable ListBox.

Anchoring - Make two components take up half of panel each

What I have:
I have a panel (the white space), and two DataGridViews represented by the green and blue squares. The panel is anchored to take up most of the center of my screen, and grows/shrinks with the window size.
What I need:
I would like the green square to always stay with it's right border in the middle of the screen and take up the left half of the screen. Equally, I'd like the blue square to stay with its left border in the middle and to take up the right half of the screen.
Basically, I just want it to always look like this image regardless.
Do I need to do this programmaticly? I can't seem to find a combination of anchoring or docking that makes this happen, and adding more panels as containers yields the same issue in the end.
Not sure if this is what you want:
Creating a SplitContainer on the screen.
Anchor = Top, Bottom, Left, Right
IsSplitterFixed = True (Trick)
Creating another two datagridviews, each a side inside the SplitterContainer
Dock = Fill
I generally use a TableLayoutPanel to accomplish this. It is very easy to use (a simple introduction can be found here).
You create to cells in the first row and set it to 50% width each. In each cell you put one DataGrid and you set their Dock'ing to Fill.
I tried the solution with the TableLayoutPanel, which works ok.
But layouting inside the TableLayoutPanel is a bit unhandy and restricted if you want to use different positioning.
I found another solution which does it with a little of programming effort:
For the left item define anchoring to left
For the right item define no left/right anchoring
This leads into the left item remaining at its location when resizing the form and the right to move staying about the middle location.
The I added an OnSizeChanged handler to the form, which implements these lines:
int widthForItem = Item2.Left - Item1.Left; // you can subtract a distance here
Item1.Width = widthForEachItem;
Item2.Width = widthForEachItem

scroll bar TableLayoutPanel c#

I have a TableLayoutPanel that has several TableLayoutPanels inside it. The amount changes dynamically and will almost always be too many to be able to fit inside the form.I need it to have a scroll bar so I can view the entire component.
I have tried setting the autoscroll property on the main panel to true and docking it and/or setting a maximum size. What the controler does instead, is to try and fit ALL of the Panel inside the form therefore changing the size of its inside components and squeezing them all together instead of creating a scroll bar to scroll through my Panel.
Do you guys know what I might be doing wrong?
Thanks.
Jose
PS: I am using VS 2010
I had the same issue one day and found out that the problem was that I had a "MinimumSize" set to the TableLayoutPanel. That caused the control to keep a minimum height no matter what the Dock and/or Anchor constraints, preventing the AutoScroll feature to work properly. Since that feature is based on a simple check on the Y coordinates of all children controls of a control against that control's height, the scrollbar was not appearing despite the fact the the TableLayoutPanel's child controls were "disapearing" out of sight due to its parent control clip area.
So in other words, check the MinimumSize property of TableLayoutPanel and make sure it's empty.
Maybe this will help.
if it still doesn't work, try put a panel and then put the tableLayoutPanel into that panel. Set to true the autoScroll property of the panel.
I had the same thing happen on my project. All my controls were squished inside the TableLayoutPanel. In my case, I was rendering many of the controls as ColumnStyle.Percent. Switching this to ColumnStyle.Autosize was the fix I needed.
I assume you've set these properties as well, but just in case my TableLayoutPanels also use the following settings:
AutoSize = true;
AutoSizeMode = AutoSizeMode.GrowAndShrink;
AutoScroll = true;
Late answer, but I've been fighting with a complex layout recently and was looking for a solution to get my scrolling working on a screen with far too many fields. Honestly, better design should avoid this problem 99% of the time but sometimes your hands are just tied.
The Problem
The problem seems to be that if you're nested too deeply with multiple grids, groups, and panels they stop reporting properly to parent controls that their contents have overflown the size of the current screen. Actually, the problem is probably that the controls are all set to dock fill and do fit within their parent control, so the top level control doesn't know that the contents of its great-great-great-great-grandchild controls don't fit.
Solution
The trick to fix this seems to be manually forcing the top most panel to scroll at a certain minimum size:
MainPanel.AutoSize = true;
MainPanel.AutoScrollMinSize = new Size(400, 500);
TableLayoutPanel scrolling is full of bugs.
The solution to make it work correctly is here.

Categories