I am currently working on my first WPF project and trying to make a ListView
scrollable. At first I thought this could be easily done by simply limiting the ListView
's width and height and thus forcing a scrollbar to appear automatically whenever the content exceeds its space. This seemed fine at first but due to the handled PreviewMouseDown
event (which enables dragging the list's items) it doesn't work after selecting an item.
Second attempt (using ScrollViewer
)
<ScrollViewer>
<ListView ItemsSource="{Binding FileViewModels}"
PreviewMouseDown="ListView_MouseMove"
Height="450" Width="200"/>
</ScrollViewer>
Of course, this resulted in a second scrollbar whenever the list's content became larger than its max height. And dragging the bar still didn't work after selecting an item.
Third (quite foolish) attempt (disabling scrollbar duplicate)
<ScrollViewer>
<ListView ItemsSource="{Binding FileViewModels}"
PreviewMouseDown="ListView_MouseMove"
Height="450" Width="200"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"/>
</ScrollViewer>
This removed the scrollbar duplicate and enabled scrolling via mouse wheel but disabled the scrollbar, so you couldn't move by clicking and dragging it.
Fourth attempt (constant size of the ScrollViewer
)
<ScrollViewer Height="450" Width="200">
<ListView ItemsSource="{Binding FileViewModels}"
PreviewMouseDown="ListView_MouseMove"/>
</ScrollViewer>
Removed the width/height constraint from the ListView
and moved it to the ScrollViewer
. This enables the scrollbar and removes the duplicate. Unfortunately the mouse wheel doesn't work anymore (dragging the scroll bar works fine).
Could somebody please explain to me why the mouse wheel doesn't work anymore and how to fix this?
Edit Maybe I should go back to my first solution.
Obviously, the ListView
's template already contains a ScrollViewer
. The remaining problem would then be that I cannot drag the scrollbar after selecting an item because of the handled PreviewMouseDown
event (scrolling via MouseWheel still works in that case). Should I handle the dragging of items differently (it worked fine for me, before wanting to add a scrollbar)? Or is there a way to detect if the cursor is above the scrollbar (so I could then deselect the item which enables scrolling)? Or are there any other suggestions?
This may help you..
private void ListViewScrollViewer_PreviewMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
{
ScrollViewer scv = (ScrollViewer)sender;
scv.ScrollToVerticalOffset(scv.VerticalOffset - e.Delta);
e.Handled = true;
}
This would probably be the most comfortable solution:
<ListView.Template>
<ControlTemplate>
<ScrollViewer>
<ItemsPresenter></ItemsPresenter>
</ScrollViewer>
</ControlTemplate>
</ListView.Template>
For me this worked:
<ListView.Template>
<ControlTemplate>
<!-- Empty template to allow ScrollViewer to capture mouse scroll -->
<ItemsPresenter />
</ControlTemplate>
</ListView.Template>
instead of this:
<ListView.Template>
<ControlTemplate>
<ScrollViewer>
<ItemsPresenter></ItemsPresenter>
</ScrollViewer>
</ControlTemplate>
</ListView.Template>
<ScrollViewer Background="Transparent">
If Background
is null, the mouse wheel will not work on ScrollViewer
. You can set the Background
to Transparent
or some other value.
In my case this helped:
<ScrollViewer ScrollViewer.CanContentScroll="True" ScrollViewer.VerticalScrollBarVisibility="Disabled" ScrollViewer.HorizontalScrollBarVisibility="Auto" >
<DataGrid x:Name="dataGrid" SelectionMode="Single" ItemsSource="{Binding}" SelectedValuePath="{Binding Item}" AutoGenerateColumns="True">
</DataGrid>
</ScrollViewer>
The design was disabling VerticalScrollBarVisibility
attribute in outer scope , ie in ScrollViewer
.
I want to add some comment to the solution Rocky provided. It worked fine for me, but later I needed to use it in a different window to scroll Grid
. I faced a problem: the ScrollViewer
did not scroll to the bottom end. The reason was because of attempts to set the invalid VerticalOffset
value. The code below works fine for me (just need to change PreviewMouseWheel
handler:
private void UIElement_OnPreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
ScrollViewer scroll = (ScrollViewer)sender;
if (e.Delta < 0)
{
if (scroll.VerticalOffset - e.Delta <= scroll.ExtentHeight - scroll.ViewportHeight)
{
scroll.ScrollToVerticalOffset(scroll.VerticalOffset - e.Delta);
}
else
{
scroll.ScrollToBottom();
}
}
else
{
if (scroll.VerticalOffset + e.Delta > 0)
{
scroll.ScrollToVerticalOffset(scroll.VerticalOffset - e.Delta);
}
else
{
scroll.ScrollToTop();
}
}
e.Handled = true;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.