WPF ScrollViewer horizontal scrolling with buttons - c#

I have a ListBox with horizontal orientation inside a ScrollViewer. When the list grows, it automatically scrolls to the last element. The scrollbars work, however must be disabled for this. I need to have separate buttons which would scroll the ScrollViewer by a predetermined iteration (much like buttons on the scrollbars). For this, I have tried:
sv.ScrollToHorizontalOffset(sv.HorizontalOffset + 20);
However, the ScrollViewer's HorizontalOffset seems to always be 0, and the method doesn't do anything with any values.
sv.LineRight();
sv.LineLeft();
both don't work, probably because the only child element is the ListBox.
If I change the ListBox's orientation to vertical, then the ScrollViewer's VerticalOffset changes with scrolling/adding new elements, and ScrollToVerticalOffset works correctly. Why is this different with horizontal orientation? Any other solutions?
Note: this was done without using XAML to place the controls.

To make this work, you need to do a couple things:
Remove the outer ScrollViewer and just use the ScrollViewer that is built into the ListBox.
On the ListBox set the following properties:
ScrollViewer.CanContentScroll="False"
This will make the HorizontalOffset property work in pixels. When it is set to True it works in items.
ScrollViewer.HorizontalScrollBarVisibility="Hidden"
This will keep scrolling active but will hide the scrollbar.
In your code you can get the ScrollViewer of the ListBox like so. In this example my ListBox is named x:Name="ListBox".
var scrollViewer = ListBox.FindChildByType<ScrollViewer>();
Finally, you can set the offset like below. In my sample, I created a method and passed in a value from my button click event handlers.
private void ScrollHorizontally(double offset)
{
var scrollViewer = ListBox.FindChildByType<ScrollViewer>();
scrollViewer?.ScrollToHorizontalOffset(scrollViewer.HorizontalOffset + offset);
}

Related

Making a StackPanel scrollable in Windows Phone 8

I have a list of controls, put into a stackpanel. These controls are Hubtiles, that are added programatically after a user creates it - a list essentially. I need to make the StackPanel in which they are added, scrollable - what would be the best approach for this? Should i put the stackpanel inside a ScrollView, and then increase the StackPanels height with the actual height of the Hubtile - to make it scrollable, but not so that the user can scroll infinite without something being there. So whenever the amount of controls inside the StackPanel reaches 3, it'll automatically increase it's height like this:
Whenever the amount of controls inside the StackPanel reaches 3 or above:
StackPanel.Height = StackPanel.Height + Hubtile.ActualHeight;
Thanks a lot!
Just put the StackPanel into ScrollViewer, set the StackPanel.VerticalAlignment to Stretch and set fixed size to the parent ScrollViewer. This is necessary - the ScrollViewer must know its size, to show the scrollbars for the inner content when the inner content is too long.

Winform: Panel with scroll needs to have their width/height defined?

I've a winform usercontrol, that has a Panel, which is containing some TableLayout(which have also some other user controls).
All my components have a Dock=Fill and Autosize=True properties.
Currently, when I resize the windows, I don't have any scrollbar, the overflow is just no show.
I found that if I set the AutoScrollMinSize of my panel to something, I'm having those scrollbar appearing when I reach the set size.
My problem is that I add/remove elements on runtime, and I've also some things that I display or not depending the configuration. So for me it's very hard to hardcode here a value, either I've scrollbar too soon, or too late.
I'm sure there should be a way to configure my userControl, without having to calculate myself the size, to have the component displaying scrollbar, when the children's content cannot be displayed, do you know how?
Thank you!
You can change the AutoScrollMinSize value on the panel resize event or the form's resize event. That way, it won't be a fixed value and there will be a scrollbar available if the panel's child controls go beyond the panel edges -
private void panel1_Resize(object sender, EventArgs e)
{
panel1.AutoScrollMinSize = new System.Drawing.Size(panel1.Width, panel1.Height);
}

Partially vertically scroll

I have a ListBox that contains two columns - column one contains a Toggle Button, column two contains an Expander with multiple controls within it. If the expander is collapsed, the overall scrolling of the ListBox works fine. However, if the Expander is open and the expander contains a large quantity of items, the ListBox will scroll the entire row size, often not showing part of the expander list.
This would be similar to placing an image in the list box that is larger than the viewable area of the list box. In this case, if you click the scrollbar, you would want to "step" down the image, without it scrolling off the screen in one click.
Is there a setting for the ListBox that will allow the partial scrolling as I've described? My listBox is defined in a xaml, the controls are added via C# code.
Have you tried turning on smooth scrolling by setting ScrollViewer.CanContentScroll to false? This is what controls whether the ScrollViewer will scroll an item at a time, or smoothly with partial items available.
"ScrollViewer currently allows two scrolling modes: smooth
pixel-by-pixel scrolling (CanContentScroll = false) or discrete
item-by-item scrolling (CanContentScroll = true). Currently WPF
supports UI virtualization only when scrolling by item. Pixel-based
scrolling is also called 'physical scrolling' and item-based scrolling
is also called 'logical scrolling'."
(From this answer).
If you have a lot of items in your ListBox, this may not be an ideal solution, however, because it turns off Virtualization, and therefore may have a performance impact. Take a look at this answer to see more about smooth scrolling and virtualization. (One answer suggests a hack that allows for smooth scrolling and virtualization).

Determine the visibility of a control on screen

Lets say, I've a ListBox with hundreds of ListBoxItems. On the right side of the ListBox, there is a ScrollViewer which allows the user to see the items above or underneath in the current view of the ListBox. My goal is now to determine which elements i.e. ListBoxItems are currently visible. Is there a method to determine if a ListBoxItem is visible on the screen?
You can use ListBox.ScrollIntoView() to ensure a ListBoxItem is visible.
Can you use this rather than checking if it is visible?
You may use ListView instead of ListBox, since ListBoxItem's have a property called Bounds, which allow you to see the client coordinates of each item by returning a Rectangle object. Afterwards, you can compare these coordinates to the ListView's visible client area to determine if an item is visible or not. The visible area in a listview would be from x=0 to x=Width and from y=0 to y=Height. You can quickly test for visibility by using Rectangle.IntersectsWith(Rectangle)...

Prevent ListView from Resizing Window When Adding Items WPF/C#

I have a ListView in WPF that is resizing my entire application window whenever I add items to it. I have the ListView size bound to the grid it is in, which is bound to the window size. So when the user resizes the window, the ListView grows. The problem is that when I add items to the ListView, it automatically stretches to try to fit the new content, which in turn stretches the size of the entire window.
Is there anyway to prevent this behavior from happening?
Change SizeToContent of your window to Manual or Width (no Height should be there). This would prevent window itself from changing its height automatically according to content.
You want to set the VerticalAlignment property to 'Stretch'. If necessary, in the parent control too, and so on, until you are in the Window control.
The caveat is that if one of the controls on the way up is a StackPanel, it will not stretch to fit, but ALWAYS expand to accommodate its content. So stay away from StackPanels, use Stretch, and you're set!
Remove your Bindings too, they are likely TwoWay: So the listview increasing its size is making your Window grow!
Hope that helps!
You can use the following code.
First get the value of listview onload. Then store it in a variable, then do this code in the ColumnWidthChanging event property like this:
e.cancel = true;
e.NewWidth = // the declared variable in which you store the list view with value in the onload function of the form
int a = 100;
e.cancel =true;
e.NewWidth = a;
Have you tried setting the MaxWidth property?
You can set the MaxHeight property for your ListView in your xaml, no?
10 years later...
Put the ListView inside a flexible control which resizes as you resize the window, for example, a Border. This way, when the Window resizes, the Border resizes, and when the Border resizes, the ListView resizes.
Bind the MaxHeight property of the ListView to the ActualHeight property of the Border. This way, the ListView cannot resize the Border.
For details on how to achieve this, see this answer (to a practically duplicate question which is also about 10 years old): https://stackoverflow.com/a/68498797/773113

Categories

Resources