Rzeczywiście jest możliwe zrobienie tego, o co prosisz, choć będzie to wymagało sporo niestandardowego kodu.
Zwykle w WPF ScrollViewer wykorzystuje tzw. Przewijanie logiczne, co oznacza, że będzie przewijany przedmiot po elemencie, a nie o wartość przesunięcia. Pozostałe odpowiedzi obejmują niektóre sposoby zmiany zachowania przewijania logicznego na działanie przewijania fizycznego. Innym sposobem jest wykorzystanie metod ScrollToVertialOffset i ScrollToHorizontalOffset odsłoniętych zarówno przez ScrollViwer, jak i IScrollInfo.
Aby zaimplementować większą część, przewijanie po naciśnięciu kółka myszki będzie wymagało użycia zdarzeń MouseDown i MouseMove.
<ListView x:Name="uiListView"
Mouse.MouseDown="OnListViewMouseDown"
Mouse.MouseMove="OnListViewMouseMove"
ScrollViewer.CanContentScroll="False">
....
</ListView>
W MouseDown, mamy zamiar nagrać aktualną pozycję myszy, które będziemy używać jako względna punktu w celu określenia w jakim kierunku możemy przewijać. W ruch myszy, mamy zamiar dostać komponent ScrollViwer ListView, a następnie Przewiń go odpowiednio.
private Point myMousePlacementPoint;
private void OnListViewMouseDown(object sender, MouseButtonEventArgs e)
{
if (e.MiddleButton == MouseButtonState.Pressed)
{
myMousePlacementPoint = this.PointToScreen(Mouse.GetPosition(this));
}
}
private void OnListViewMouseMove(object sender, MouseEventArgs e)
{
ScrollViewer scrollViewer = ScrollHelper.GetScrollViewer(uiListView) as ScrollViewer;
if (e.MiddleButton == MouseButtonState.Pressed)
{
var currentPoint = this.PointToScreen(Mouse.GetPosition(this));
if (currentPoint.Y < myMousePlacementPoint.Y)
{
scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - 3);
}
else if (currentPoint.Y > myMousePlacementPoint.Y)
{
scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset + 3);
}
if (currentPoint.X < myMousePlacementPoint.X)
{
scrollViewer.ScrollToHorizontalOffset(scrollViewer.HorizontalOffset - 3);
}
else if (currentPoint.X > myMousePlacementPoint.X)
{
scrollViewer.ScrollToHorizontalOffset(scrollViewer.HorizontalOffset + 3);
}
}
}
public static DependencyObject GetScrollViewer(DependencyObject o)
{
// Return the DependencyObject if it is a ScrollViewer
if (o is ScrollViewer)
{ return o; }
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(o); i++)
{
var child = VisualTreeHelper.GetChild(o, i);
var result = GetScrollViewer(child);
if (result == null)
{
continue;
}
else
{
return result;
}
}
return null;
}
Jest to niektóre obszary pozbawione jak to tylko proof of concept ale powinien zdecydowanie należy zacząć w dobrym kierunku. Aby mieć ciągłe przewijanie po przesunięciu myszy od początkowego punktu MouseDown, logika przewijania mogła przejść do DispatcherTimer lub czegoś podobnego.
Dzięki Pop. Czym jest wirtualizacja? –
Wirtualizacja polega na tym, że zawartość wewnątrz obiektu VirtualizingStackPanel (który jest domyślnym ItemPanelem dla ListBox i tym podobnych) nie renderuje układu elementów do/dopóki element nie jest widoczny. Dzięki licznym lub wizualnie złożonym elementom może znacznie zwiększyć wydajność, ponieważ generuje tylko ui za niewielki procent. Więcej informacji tutaj: http://msdn.microsoft.com/en-us/library/system.windows.controls.virtualizingstackpanel.aspx – rmoore
Powoduje to przełączenie z przewijania logicznego na fizyczne (zakładając, że używasz StackPanel, który implementuje IScrollInfo). Jeśli nadal chcesz logiczne przewijanie, ale aby go wygładzić, to nie pomoże – Schneider