Flickering scrollbars in ScrollableControl - c#

I've got this UserControl derived from ScrollableControl and I only wish to show a vertical scrollbar. As by no means I can configure to only show the vertical scrollbar, no matter what. It seems like a flaw of winforms. Another problem is that whenever the parent resizes, making the control less wide, the horizontal scrollbar is shown immediately until the OnResize event handler adjusts the width. As a result the horizontal scrollbar flickers, as its contents it temporary wider than the width of the scrollabe control. This makes the components inside the scrollable control redraw unnecessary times as they adjust to the available space. When the control is made wider, the horizontal scrollbar is never shown.
So I googled around and found this: Add vertical scroll bar to panel in .NET
Seems promosing, but now both scrollbars, and the contents of the panel are flickering whenever it is scrolled by this external scrollbar. The problem of resizing the panel to become less width, showing and hiding the horizontal scrollbar, and causing unnecessary redraws is no more though, so thats a win.
This is what the constructor of the control looks like:
public BarGraphPanel()
{
this.HScroll = false;
this.VScroll = false;
this.AutoScroll = false;
this.VerticalScroll.Visible = false;
this.HorizontalScroll.Visible = false;
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.SetStyle(ControlStyles.ResizeRedraw, true);
this.DoubleBuffered = true;
}
What it should look like while scrolling:
What it looks like while scrolling:
That the textboxes aren't drawn so nicely while scrolling is something I can accept, but both scrollbars flickering (so temporary showing actually 3 scrollbars!) is madness.
Is there a way of only having one scrollbar on screen (always) without any of the other bars or its contents flickering?

The answer of MajinFro here actually helped me out: During FlowLayoutPanel scrolling, background distorts + flickers
When I do not override CreateParams as suggested, it doesn't work, so that does seem like a essential 'trick'.

set on panel scrolling event this code:
private void panel1_Scroll(object sender, ScrollEventArgs e)
{
panel1.Invalidate();
}

Related

FlowLayoutPanel scrollbar doesn't disapear properly sometimes

I am facing a really strange issue and after googling and searching in StackOverflow i absolutly have no clue how to fix that because it only happens sometimes.
My Problem:
I have a flowLayoutPanel (flp) and only a the vertical scrollbar if controls inside my flp doesnt fit it's size. I don't use a horizontal scrollbar.
Code for that:
private void setFlowcontrolScrollbar(flowLayoutPanel fc)
{
int height = 0;
foreach (FilePanel fp in fc.Controls)
{
height += fp.Height;
}
if (height > fc.Height)
{
fc.VerticalScroll.Visible = true;
fc.VerticalScroll.Enabled = true;
}
else
{
fc.VerticalScroll.Visible = false;
fc.VerticalScroll.Enabled = false;
}
fc.HorizontalScroll.Visible = false;
fc.HorizontalScroll.Enabled = false;
}
This method is called after the flp was resized or new items were added to it. Controls in my flp are resized only in horizontal direction.
Now this works fine, i can scroll if there are to many controls in my flp. But let's say i have lot's of controls in my flp (=> vertical scrollbar enabled,visible) and now i delete some controls so i would not need a scrollbar anymore. Functional everything works fine, i cant scroll or click on a scrollbar. But sometimes there is a visual bug. The scrollbar doesn't disapear and i can do strange things like in this picture:
If i also call void setFlowcontrolScrollbar after removing a control this happens almost all the time when i remove a control and scrollbar is not needed any more:
In both pictures i resized my form a bit to the right so you can see how my controls overlap with the scrollbar. How do i fix that? Is there a better way to only activate vertical scroll?
IMPORTANT EDIT:
Bug only occurs if i use drag'n'drop to remove lines (controls) from my flp and only if i touched/hovered over the scrollbar while draging. If i drag it out on the left side and drop it somewhere else the scrollbar disappears correct.
Note: Found a better solution to get rid of horizontal scroll.
panel.HorizontalScroll.Maximum = 0;
panel.AutoScroll = false;
panel.VerticalScroll.Visible = false;
panel.AutoScroll = true;
(Source: How do I disable the horizontal scrollbar in a Panel , answer from "Kbv Subrahmanyam")

How to make a horizontal bar in a panel control when drawing on it?

I have a panel and I need to draw a horizontal chart on it. But sometimes the chart can be too long for the panel, even the form has maximum size. So I want to make a horizontal bar on panel to enable the user to see the remaining part of the drawing that is out of the bounds.
Chart is something like this:
As you can see, the chart is out of the panel's bounds and form's too. I don't have any idea how can it be done, so I have no code to show. So how can I do it using a basic method?
Yes, the solution is pretty basic, as long as the size you want to draw won't go over 32k pixels width:
Put your Panel inside another one.
The outer Panel has AutoScroll=true
The inner one where you draw has the size of your drawing.
You need to draw in the Paint event, as you should anyway (!)
Now the outer Panel shows a horizontal scrollbar and the user can scroll right and left and see all parts of the drawing..
One alternative would be to add a dummy control that enforces the AutoScroll of your drawing Panel to work, but I find using two Panels the cleaner way to go..
Note: You should either use a PictureBox or at least a double-buffered Panel subclass to avoid flicker and tearing:
class DrawPanel : Panel
{
public DrawPanel()
{ DoubleBuffered = true; }
}
Update: Instead of a Panel, which is a Container control and not really meant to draw onto you can use a Picturebox or a Label (with Autosize=false); both have the DoubleBuffered property turned on out of the box and support drawing better than Panels do.

Controlling RichTextBox position with other ScrollBar

I have richTextBox (dock style = fill, scrollbar = only vertical, wordwrap = false) in splitcontainer.panel1
splitcontainer.panel1.Controls.Add(richTextBox);
In case when richTextBox needs to be scrolled (when its width is bigger than width of splitcontainer.panel1).
I wish a scrollbar would appear (but in splitcontainer.panel1, not scroll bar from richTextBox).
Is it possible to handle?
It certainly doesn't make sense to do that. For the sub-panel's scrollbars to even work properly, you couldn't dock-fill the RichTextBox control. Then you would have to constantly resize the RichTextBox control based on the TextChanged event, and that could get messy.
It's also not clear why you couldn't just set the ScrollBars to both:
richTextBox.ScrollBars = RichTextBoxScrollBars.Both;
It would seem to do the job you really want it to do.

How to keep status strip visible wherever user scrolls

I have a form with status strip. Form has auto-scroll on. When required, scrollbars appear and user can scroll.
However when the content is bigger than form size and user has to scroll down to see other parts of the content, he/she has to scroll all the way down also to see the status strip.
I want to keep the status strip on the bottom of the form whatever the size and scroll position is. How do I do that?
Why can I not put everything on a panel and set panel.AutoScroll = true?
Because I draw everything on this panel (with GDI+), then resize it, then form displays scrollbars. Now if I set autoscroll on in the panel no scroll bars are shown because there are no controls on panel, only GDI+ drawings.
Put everything that needs scrolling inside a panel and set auto-scroll on the panel. Your status strip should go outside the panel.
If you are doing extensive drawing with GDI+, there are two good options that I can think of to replace your design.
If the user must interact with your graphics, consider creating a custom control to encapsulate the functionality and graphics.
If it is nothing but a display of some data, you can draw your graphics to a Bitmap and view it in a PictureBox.
I don't know what you are trying to accomplish, so I can't say what is the correct solution.
It sounds like you are doing things backwards. The "Form" shouldn't be showing the scrollbars, the panel should be.
If the "content" of your panel is larger than your panel, and you are doing all of this drawing inside the panel, then you need to set the panel's AutoScrollMinSize to the size of your content, not keep enlarging the size of the panel.
Set the size of your panel's content (example):
panel1.AutoScrollMinSize = new Size(500, 500);
Then in your panel's paint event, apply the transformation:
private void panel1_Paint(object sender, PaintEventArgs e) {
e.Graphics.TranslateTransform(panel1.AutoScrollPosition.X, panel1.AutoScrollPosition.Y);
// do your normal painting here
}
Use a Double-Buffered panel to avoid flicker.
Your StatusStrip should just be docked to the bottom of the form, not interfering with the panel.

Making control docking and scrollbars play nicely

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;
}

Categories