C# 如何在 WPF 数据网格上自动滚动
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1027051/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to autoscroll on WPF datagrid
提问by Christian Ruppert
I think I am stupid. I searched now for 15 minutes, and found several different solutions for scrolling on datagrids, but none seems to work for me.
我觉得我很傻。我现在搜索了 15 分钟,并找到了几种不同的在数据网格上滚动的解决方案,但似乎没有一个对我有用。
I am using WPF with .NET 3.5 and the WPF Toolkit DataGrid. My grid gets updated when my observable collection changes, works perfectly. Now, my DataGrid is located inside a normal Grid and scrollbars appear if the DataGrid gets too big. Also fine...
我将 WPF 与 .NET 3.5 和 WPF Toolkit DataGrid 一起使用。当我的可观察集合发生变化时,我的网格会更新,完美运行。现在,我的 DataGrid 位于普通 Grid 内,如果 DataGrid 太大,则会出现滚动条。也不错...
And now comes the 1.000.000 $ question:
现在是 1.000.000 美元的问题:
How do I get the datagrid to scroll to the last row? There is:
如何让数据网格滚动到最后一行?有:
- no AutoScroll Property
- no CurrentRowSelected Index
- a CurrentCell, but no Collection I could use for CurrentCell = AllCells.Last
- 没有 AutoScroll 属性
- 没有 CurrentRowSelected 索引
- 一个 CurrentCell,但没有我可以用于 CurrentCell = AllCells.Last 的集合
Any ideas? I feel really stupid, and it seems strange that this question is so hard. What am I missing?
有任何想法吗?我真的觉得自己很傻,这个问题这么难似乎也很奇怪。我错过了什么?
采纳答案by Joseph jun. Melettukunnel
;)
;)
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();
}
}
回答by Justin Niessner
What you need is to get the reference to the ScrollViewer object for your DataGrid. You can then manipulate the VerticalOffset property to scroll to the bottom.
您需要的是获取对 DataGrid 的 ScrollViewer 对象的引用。然后您可以操纵 VerticalOffset 属性滚动到底部。
To add even more flare to your app...you could add a Spline animation to the scroll so everything looks up to par with the rest of the application.
要向您的应用程序添加更多光晕……您可以向滚动添加样条动画,以便一切看起来都与应用程序的其余部分相匹配。
回答by Aran Mulholland
You should use the datagrid method
您应该使用数据网格方法
datagrid.ScrollIntoView(itemInRow);
or
或者
datagrid.ScrollIntoView(itemInRow, column);
this way provides no messing around finding the scroll viewer etc.
这种方式不会在查找滚动查看器等方面造成混乱。
回答by azze
listbox.Add(foo);
listbox.SelectedIndex = count - 1;
listbox.ScrollIntoView(listbox.SelectedItem);
listbox.SelectedIndex = -1;
回答by TRS Rao
if large data datagrid.ScrollIntoView(itemInRow, column); not works fine then we need to use below one only:
如果大数据 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();
}
}
回答by PILuaces
If you are using MVVMpattern, you can have a combination of this article with this other: http://www.codeproject.com/KB/WPF/AccessControlsInViewModel.aspx.
如果您使用的是MVVM模式,则可以将本文与其他文章结合使用:http: //www.codeproject.com/KB/WPF/AccessControlsInViewModel.aspx。
The idea is to use attached properties to access the control in your ViewModel class. Once you do that, you would need to check that the datagrid is not null, and it has any items.
这个想法是使用附加属性来访问 ViewModel 类中的控件。一旦你这样做了,你需要检查数据网格不为空,并且它有任何项目。
if ((mainDataGrid != null) && (mainDataGrid.Items.Count > 0)){
//Same snippet
}
回答by Anas
For having an AutoScroll To the Last element added :
添加 AutoScroll To the Last 元素:
YourDataGrid.ScrollIntoView(YourDataGrid.Items.GetItemAt(YourDataGrid.Items.Count-1));
May This Help :)
可能会有所帮助:)
回答by Denis Susloparov
I've written an attached property for grid autoscroll:
我为网格自动滚动编写了一个附加属性:
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);
}
}
Usage:
用法:
<DataGrid c:DataGridBehavior.Autoscroll="{Binding AutoScroll}"/>
回答by James Esh
I know this is a late answer, but just for the people that are searching around, I found THE EASYEST way to scroll to the bottom of a DataGrid. in the DataContextChanged
event put this in:
我知道这是一个迟到的答案,但仅对于正在搜索的人来说,我找到了滚动到 DataGrid 底部的最简单方法。在DataContextChanged
事件把这个在:
myDataGrid.ScrollIntoView(CollectionView.NewItemPlaceholder);
Easy huh?
容易吧?
This is why it works: On every data grid there is a place at the bottom of the DataGrid where you can add a new item to your list that it's bound to. That is a CollectionView.NewItemPlaceholder
, and there will only be one of those in your DataGrid. So you can just scroll to that.
这就是它起作用的原因:在每个数据网格上,DataGrid 底部都有一个位置,您可以在其中将新项目添加到它所绑定到的列表中。那是一个CollectionView.NewItemPlaceholder
,并且您的 DataGrid 中只会有一个。所以你可以滚动到那个。
回答by Steve Brother
Actually...
实际上...
I had the same problem as well when I was learning about Collection Views about doing DataContext in WPF.
当我学习在 WPF 中执行 DataContext 的集合视图时,我也遇到了同样的问题。
I too was faced with a task of slapping together a WPF program that I need to programmically to move up and down on the DataGrid using buttons since I needed to put it on a resistive touchscreen ONLY for the production builders \t my company, and there's no mouse or keyboard for them to use.
我也面临着将 WPF 程序拼凑在一起的任务,我需要以编程方式使用按钮在 DataGrid 上上下移动,因为我需要将它放在电阻式触摸屏上,仅适用于我的公司的生产制造商,还有没有鼠标或键盘供他们使用。
But this example worked for me using the ScrollIntoView
method as previously mentioned in this post:
但是这个例子使用本文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);
}
Where Orders is a List<T>
collection
Orders 是一个List<T>
集合
in XAML:
在 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>
Do follow the previous advice and keep the DataGrid by itself and not in a stack panel. For the Row Definition for the DataGrid (the third row in this case), I set the Height at 150, and the scrollbar works.
请遵循之前的建议,将 DataGrid 单独保留而不是在堆栈面板中。对于 DataGrid 的 Row Definition(在本例中为第三行),我将 Height 设置为 150,并且滚动条有效。