[英]How to autoscroll on WPF datagrid
我覺得我很傻。 我現在搜索了 15 分鍾,並找到了幾種不同的在數據網格上滾動的解決方案,但似乎沒有一個對我有用。
我將 WPF 與 .NET 3.5 和 WPF Toolkit DataGrid 一起使用。 當我的可觀察集合發生變化時,我的網格會更新,完美運行。 現在,我的 DataGrid 位於普通 Grid 內,如果 DataGrid 太大,則會出現滾動條。 也不錯...
現在是 1.000.000 美元的問題:
如何讓數據網格滾動到最后一行? 有:
有任何想法嗎? 我真的覺得自己很傻,這個問題這么難似乎也很奇怪。 我錯過了什么?
您應該使用數據網格方法
datagrid.ScrollIntoView(itemInRow);
要么
datagrid.ScrollIntoView(itemInRow, column);
這種方式不會在查找滾動查看器等方面造成混亂。
;)
if (mainDataGrid.Items.Count > 0)
{
var border = VisualTreeHelper.GetChild(mainDataGrid, 0) as Decorator;
if (border != null)
{
var scroll = border.Child as ScrollViewer;
if (scroll != null) scroll.ScrollToEnd();
}
}
我為網格自動滾動編寫了一個附加屬性:
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Controls;
public static class DataGridBehavior
{
public static readonly DependencyProperty AutoscrollProperty = DependencyProperty.RegisterAttached(
"Autoscroll", typeof(bool), typeof(DataGridBehavior), new PropertyMetadata(default(bool), AutoscrollChangedCallback));
private static readonly Dictionary<DataGrid, NotifyCollectionChangedEventHandler> handlersDict = new Dictionary<DataGrid, NotifyCollectionChangedEventHandler>();
private static void AutoscrollChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
{
var dataGrid = dependencyObject as DataGrid;
if (dataGrid == null)
{
throw new InvalidOperationException("Dependency object is not DataGrid.");
}
if ((bool)args.NewValue)
{
Subscribe(dataGrid);
dataGrid.Unloaded += DataGridOnUnloaded;
dataGrid.Loaded += DataGridOnLoaded;
}
else
{
Unsubscribe(dataGrid);
dataGrid.Unloaded -= DataGridOnUnloaded;
dataGrid.Loaded -= DataGridOnLoaded;
}
}
private static void Subscribe(DataGrid dataGrid)
{
var handler = new NotifyCollectionChangedEventHandler((sender, eventArgs) => ScrollToEnd(dataGrid));
handlersDict.Add(dataGrid, handler);
((INotifyCollectionChanged)dataGrid.Items).CollectionChanged += handler;
ScrollToEnd(dataGrid);
}
private static void Unsubscribe(DataGrid dataGrid)
{
NotifyCollectionChangedEventHandler handler;
handlersDict.TryGetValue(dataGrid, out handler);
if (handler == null)
{
return;
}
((INotifyCollectionChanged)dataGrid.Items).CollectionChanged -= handler;
handlersDict.Remove(dataGrid);
}
private static void DataGridOnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
var dataGrid = (DataGrid)sender;
if (GetAutoscroll(dataGrid))
{
Subscribe(dataGrid);
}
}
private static void DataGridOnUnloaded(object sender, RoutedEventArgs routedEventArgs)
{
var dataGrid = (DataGrid)sender;
if (GetAutoscroll(dataGrid))
{
Unsubscribe(dataGrid);
}
}
private static void ScrollToEnd(DataGrid datagrid)
{
if (datagrid.Items.Count == 0)
{
return;
}
datagrid.ScrollIntoView(datagrid.Items[datagrid.Items.Count - 1]);
}
public static void SetAutoscroll(DependencyObject element, bool value)
{
element.SetValue(AutoscrollProperty, value);
}
public static bool GetAutoscroll(DependencyObject element)
{
return (bool)element.GetValue(AutoscrollProperty);
}
}
用法:
<DataGrid c:DataGridBehavior.Autoscroll="{Binding AutoScroll}"/>
添加 AutoScroll To the Last 元素:
YourDataGrid.ScrollIntoView(YourDataGrid.Items.GetItemAt(YourDataGrid.Items.Count-1));
可能會有所幫助:)
listbox.Add(foo);
listbox.SelectedIndex = count - 1;
listbox.ScrollIntoView(listbox.SelectedItem);
listbox.SelectedIndex = -1;
我知道這是一個遲到的答案,但僅對於正在搜索的人來說,我找到了滾動到 DataGrid 底部的最簡單方法。 在DataContextChanged
事件中放入:
myDataGrid.ScrollIntoView(CollectionView.NewItemPlaceholder);
容易吧?
這就是它起作用的原因:在每個數據網格上,DataGrid 底部都有一個位置,您可以在其中將新項目添加到它所綁定到的列表中。 那是一個CollectionView.NewItemPlaceholder
,並且您的 DataGrid 中只會有一個。 所以你可以滾動到那個。
如果大數據 datagrid.ScrollIntoView(itemInRow, column); 不能正常工作,那么我們只需要使用以下一個:
if (mainDataGrid.Items.Count > 0)
{
var border = VisualTreeHelper.GetChild(mainDataGrid, 0) as Decorator;
if (border != null)
{
var scroll = border.Child as ScrollViewer;
if (scroll != null) scroll.ScrollToEnd();
}
}
我發現最簡單的方法是從 ScrollViewer.ScrollChanged 附加事件調用ScrollIntoView方法。 這可以在 XAML 中設置如下:
<DataGrid
...
ScrollViewer.ScrollChanged="control_ScrollChanged">
ScrollChangedEventArgs對象具有各種有助於計算布局和滾動位置(Extent、Offset、Viewport)的屬性。 請注意,當使用默認的 DataGrid 虛擬化設置時,這些通常以行/列數來衡量。
這是一個示例實現,當新項目添加到 DataGrid 時,它會保持底部項目處於視圖中,除非用戶移動滾動條以查看網格中較高的項目。
private void control_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
// If the entire contents fit on the screen, ignore this event
if (e.ExtentHeight < e.ViewportHeight)
return;
// If no items are available to display, ignore this event
if (this.Items.Count <= 0)
return;
// If the ExtentHeight and ViewportHeight haven't changed, ignore this event
if (e.ExtentHeightChange == 0.0 && e.ViewportHeightChange == 0.0)
return;
// If we were close to the bottom when a new item appeared,
// scroll the new item into view. We pick a threshold of 5
// items since issues were seen when resizing the window with
// smaller threshold values.
var oldExtentHeight = e.ExtentHeight - e.ExtentHeightChange;
var oldVerticalOffset = e.VerticalOffset - e.VerticalChange;
var oldViewportHeight = e.ViewportHeight - e.ViewportHeightChange;
if (oldVerticalOffset + oldViewportHeight + 5 >= oldExtentHeight)
this.ScrollIntoView(this.Items[this.Items.Count - 1]);
}
實際上...
當我學習在 WPF 中執行 DataContext 的集合視圖時,我也遇到了同樣的問題。
我也面臨着將 WPF 程序拼湊在一起的任務,我需要以編程方式使用按鈕在 DataGrid 上上下移動,因為我需要將它放在電阻式觸摸屏上,僅適用於我的公司的生產制造商,還有沒有鼠標或鍵盤供他們使用。
但是這個例子使用ScrollIntoView
方法對我ScrollIntoView
就像這篇文章前面提到的:
private void OnMoveUp(object sender, RoutedEventArgs e)
{
ICollectionView myCollectView = CollectionViewSource.GetDefaultView(Orders);
if (myCollectView.CurrentPosition > 0)
myCollectView.MoveCurrentToPrevious();
if (myCollectView.CurrentItem != null)
theDataGrid.ScrollIntoView(myCollectView.CurrentItem);
}
private void OnMoveDown(object sender, RoutedEventArgs e)
{
ICollectionView myCollectView = CollectionViewSource.GetDefaultView(Orders);
if (myCollectView.CurrentPosition < Orders.Count)
myCollectView.MoveCurrentToNext();
if (myCollectView.CurrentItem !=null)
theDataGrid.ScrollIntoView(myCollectView.CurrentItem);
}
其中 Orders 是List<T>
集合
在 XAML 中:
<StackPanel Grid.Row="1"
Orientation="Horizontal">
<Button Click="OnMoveUp">
<Image Source="Up.jpg" />
</Button>
<Button Click="OnMoveDown">
<Image Source="Down.jpg" />
</Button>
</StackPanel>
<DataGrid Grid.Row="2"
x:Name="theDataGrid"
ItemSource="{Binding Orders}"
ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Auto" Margin="0,0,0,5">
<< code >>
</DataGrid>
請遵循之前的建議,將 DataGrid 單獨保留而不是在堆棧面板中。 對於 DataGrid 的 Row Definition(在本例中為第三行),我將 Height 設置為 150,並且滾動條有效。
這是另一個很好的解決方案。
public sealed class CustomDataGrid : DataGrid
{
protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
{
base.OnItemsSourceChanged(oldValue, newValue);
}
protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
{
base.OnItemsChanged(e);
if (this.Items.Count > 0) this.ScrollIntoView(this.Items[this.Items.Count - 1]);
}
}
您需要的是獲取對 DataGrid 的 ScrollViewer 對象的引用。 然后您可以操縱 VerticalOffset 屬性滾動到底部。
要向您的應用程序添加更多光暈……您可以向滾動添加樣條動畫,以便一切看起來都與應用程序的其余部分相匹配。
WPF DataGrid 自動滾動
只要鼠標按鈕在按鈕控件上,就會自動滾動。
XAML
<Button x:Name="XBTNPageDown" Height="50" MouseLeftButtonDown="XBTNPageDown_MouseLeftButtonDown" MouseUp="XBTNPageDown_MouseUp">Page Down</Button>
代碼
private bool pagedown = false;
private DispatcherTimer pageDownTimer = new DispatcherTimer();
private void XBTNPageDown_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
pagedown = true;
pageDownTimer.Interval = new TimeSpan(0, 0, 0, 0, 30);
pageDownTimer.Start();
pageDownTimer.Tick += (o, ea) =>
{
if (pagedown)
{
var sv = XDG.FindVisualChild<ScrollViewer>();
sv.PageDown();
pageDownTimer.Start();
}
else
{
pageDownTimer.Stop();
}
};
}
private void XBTNPageDown_MouseUp(object sender, MouseButtonEventArgs e)
{
pagedown = false;
}
這是擴展方法
將它放在您選擇的靜態類中並添加對上面代碼的引用。
public static T FindVisualChild<T>(this DependencyObject depObj) where T : DependencyObject
{
if (depObj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child != null && child is T)
{
return (T)child;
}
T childItem = FindVisualChild<T>(child);
if (childItem != null) return childItem;
}
}
return null;
}
注意:可以移動屬性sv以避免重復工作。
任何人都有RX的方式來做到這一點?
如果你使用 dataview 作為 datagrid.datacontext,你可以使用這個:
private void dgvRecords_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
var dv = dgvRecords.DataContext as DataView;
if (dv.Count > 0)
{
var drv = dv[dv.Count - 1] as DataRowView;
dgvRecords.ScrollIntoView(drv);
}
}
以下代碼對我有用;
Private Sub DataGrid1_LoadingRow(sender As Object, e As DataGridRowEventArgs) Handles DataGrid1.LoadingRow
DataGrid1.ScrollIntoView(DataGrid1.Items.GetItemAt(DataGrid1.Items.Count - 1))
End Sub
如果您正在尋找執行自動滾動的 MVVM 方式,那么您可以使用自動滾動行為。 行為滾動到選定的項目,只需添加對 System.Windows.Interactivity.dll 的引用:
public class ScrollIntoViewBehavior : Behavior<DataGrid>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.SelectionChanged += new SelectionChangedEventHandler(AssociatedObject_SelectionChanged);
}
void AssociatedObject_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (sender is DataGrid)
{
DataGrid grid = (sender as DataGrid);
if (grid?.SelectedItem != null)
{
grid.Dispatcher.InvokeAsync(() =>
{
grid.UpdateLayout();
grid.ScrollIntoView(grid.SelectedItem, null);
});
}
}
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.SelectionChanged -=
new SelectionChangedEventHandler(AssociatedObject_SelectionChanged);
}
}
XAML
<DataGrid>
<i:Interaction.Behaviors>
<local:ScrollIntoViewBehavior/>
</i:Interaction.Behaviors>
</DataGrid>
當您將 datagridview 與滾動條一起使用時,必須使用此技術。 因為我正在嘗試其他技術。 但那些不能正常工作......
var border = VisualTreeHelper.GetChild(mainDataGrid, 0) as Decorator;
if(border != null)
{ var scroll = border.Child as ScrollViewer;
if (scroll != null) scroll.ScrollToEnd();
}
如果您使用的是MVVM模式,則可以將本文與其他文章結合使用: http : //www.codeproject.com/KB/WPF/AccessControlsInViewModel.aspx 。
這個想法是使用附加屬性來訪問 ViewModel 類中的控件。 一旦你這樣做了,你需要檢查數據網格不為空,並且它有任何項目。
if ((mainDataGrid != null) && (mainDataGrid.Items.Count > 0)){
//Same snippet
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.