ventanas ventana navegacion entre abrir c# wpf datagrid

c# - ventana - Cómo desplazarse automáticamente en la cuadrícula de datos de WPF



abrir ventana wpf c# (14)

Creo que soy estúpido. Busqué ahora durante 15 minutos y encontré varias soluciones diferentes para desplazarme por las grillas de datos, pero ninguna parece funcionar para mí.

Estoy usando WPF con .NET 3.5 y WPF Toolkit DataGrid. Mi cuadrícula se actualiza cuando cambia mi colección observable, funciona perfectamente. Ahora, mi DataGrid se encuentra dentro de una Grid normal y aparecen barras de desplazamiento si DataGrid se vuelve demasiado grande. También está bien...

Y ahora viene la pregunta de 1.000.000 $:

¿Cómo hago para que la cuadrícula de datos se desplace hasta la última fila? Ahi esta:

  • sin propiedad AutoScroll
  • sin índice CurrentRowSelected
  • una CurrentCell, pero no Collection I podría utilizar para CurrentCell = AllCells.Last

¿Algunas ideas? Me siento realmente estúpido, y me parece extraño que esta pregunta sea tan difícil. ¿Qué me estoy perdiendo?


;)

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(); } }


Actualmente...

También tuve el mismo problema cuando estaba aprendiendo acerca de Collection Views sobre cómo hacer DataContext en WPF.

También me enfrenté a la tarea de unir un programa WPF que necesito programar para mover hacia arriba y hacia abajo en el DataGrid usando botones, ya que necesitaba ponerlo en una pantalla táctil resistiva SÓLO para los fabricantes de producción de mi compañía, y hay sin mouse ni teclado para que lo usen.

Pero este ejemplo funcionó para mí usando el método ScrollIntoView como se mencionó anteriormente en esta publicación:

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); }

Donde Orders es una colección List<T>

en 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>

Siga los consejos anteriores y mantenga el DataGrid solo y no en un panel de pila. Para la definición de fila para DataGrid (la tercera fila en este caso), establezco la altura en 150 y la barra de desplazamiento funciona.


Aquí hay otra excelente solución.

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]); } }


Debe usar el método de cuadrícula de datos

datagrid.ScrollIntoView(itemInRow);

o

datagrid.ScrollIntoView(itemInRow, column);

de esta forma no se pierde el tiempo buscando el visor de desplazamiento, etc.


Descubrí que la forma más sencilla de hacerlo es llamar al método ScrollIntoView desde el evento adjunto ScrollViewer.ScrollChanged. Esto se puede establecer en XAML de la siguiente manera:

<DataGrid ... ScrollViewer.ScrollChanged="control_ScrollChanged">

El objeto ScrollChangedEventArgs tiene varias propiedades que pueden ser útiles para calcular el diseño y la posición de desplazamiento (extensión, desplazamiento, ventana gráfica). Tenga en cuenta que, por lo general, se miden en números de filas / columnas cuando se usa la configuración de virtualización DataGrid predeterminada.

Aquí hay una implementación de ejemplo que mantiene el elemento inferior a la vista a medida que se agregan nuevos elementos al DataGrid, a menos que el usuario mueva la barra de desplazamiento para ver los elementos más arriba en la cuadrícula.

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]); }


He escrito una propiedad adjunta para el desplazamiento automático de la cuadrícula:

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); } }

Uso:

<DataGrid c:DataGridBehavior.Autoscroll="{Binding AutoScroll}"/>


Lo que necesita es obtener la referencia al objeto ScrollViewer para su DataGrid. A continuación, puede manipular la propiedad VerticalOffset para desplazarse hacia la parte inferior.

Para agregar aún más brillo a su aplicación ... podría agregar una animación de Spline al desplazamiento para que todo se vea a la par con el resto de la aplicación.


Por tener agregado un AutoScroll To the Last:

YourDataGrid.ScrollIntoView(YourDataGrid.Items.GetItemAt(YourDataGrid.Items.Count-1));

Puede esta ayuda :)


Sé que esta es una respuesta tardía, pero solo para las personas que están buscando, encontré la forma más FÁCIL de desplazarme hacia la parte inferior de un DataGrid. en el evento DataContextChanged , coloca esto en:

myDataGrid.ScrollIntoView(CollectionView.NewItemPlaceholder);

Fácil, ¿eh?

Es por eso que funciona: en cada cuadrícula de datos hay un lugar en la parte inferior de DataGrid donde puede agregar un nuevo elemento a la lista a la que está vinculado. Es un CollectionView.NewItemPlaceholder , y solo habrá uno de ellos en su DataGrid. Entonces puedes desplazarte a eso.


Si está utilizando el patrón MVVM , puede tener una combinación de este artículo con este otro: http://www.codeproject.com/KB/WPF/AccessControlsInViewModel.aspx .

La idea es usar propiedades adjuntas para acceder al control en tu clase de ViewModel. Una vez que lo haga, deberá verificar que la cuadrícula de datos no sea nula y que tenga algún elemento.

if ((mainDataGrid != null) && (mainDataGrid.Items.Count > 0)){ //Same snippet }


Si utilizó dataview para datagrid.datacontext, puede usar esto:

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); } }


si es grande data datagrid.ScrollIntoView (itemInRow, column); no funciona bien, entonces tenemos que usar debajo de uno solo:

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(); } }


WPF DataGrid Desplazamiento automático

Desplazamiento automático siempre que el botón del mouse esté presionado sobre un botón.

El XAML

<Button x:Name="XBTNPageDown" Height="50" MouseLeftButtonDown="XBTNPageDown_MouseLeftButtonDown" MouseUp="XBTNPageDown_MouseUp">Page Down</Button>

El código

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; }

Este es el método de extensión

Colóquelo en una clase estática de su elección y agregue referencia al código anterior.

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; }

NOTA: La propiedad sv puede moverse para evitar el trabajo repetido.

Alguien tiene una forma de RX para hacer esto?


listbox.Add(foo); listbox.SelectedIndex = count - 1; listbox.ScrollIntoView(listbox.SelectedItem); listbox.SelectedIndex = -1;