visual studio sirve que puede presentacion para hacer ejemplos desventajas con animaciones wpf vb.net datagrid scrollviewer

studio - Desplácese WPF DataGrid para mostrar el elemento seleccionado en la parte superior



visual studio wpf (3)

Tengo un DataGrid con muchos elementos y necesito desplazarme programáticamente al SelectedItem . He buscado en StackOverflow y Google, y parece que la solución es ScrollIntoView, de la siguiente manera:

grid.ScrollIntoView(grid.SelectedItem)

que desplaza el DataGrid hacia arriba o hacia abajo hasta que el elemento seleccionado esté enfocado. Sin embargo, dependiendo de la posición de desplazamiento actual relativa al elemento seleccionado, el elemento seleccionado puede terminar siendo el último elemento visible en el ScrollViewer de DataGrid. Quiero que el elemento seleccionado sea el primer elemento visible en ScrollViewer (suponiendo que haya suficientes filas en DataGrid para permitir esto). Así que probé esto:

''FindVisualChild is a custom extension method that searches in the visual tree and returns ''the first element of the specified type Dim sv = grid.FindVisualChild(Of ScrollViewer) If sv IsNot Nothing Then sv.ScrollToEnd() grid.ScrollIntoView(grid.SelectedItem)

Primero me desplazo hasta el final de DataGrid y solo entonces me desplazo al SelectedItem, en cuyo punto se muestra SelectedItem en la parte superior de DataGrid.

Mi problema es que desplazarse hasta el final de DataGrid funciona bien, pero el desplazamiento posterior al elemento seleccionado no siempre funciona.

¿Cómo puedo resolver este problema, o hay alguna otra estrategia alternativa para desplazarse a un registro específico en la posición superior?


Estaba en el camino correcto, simplemente intente trabajar con la vista de colección en lugar de trabajar directamente en la cuadrícula de datos para este tipo de necesidades.

Aquí hay un ejemplo de trabajo donde siempre se muestra el elemento deseado como el primer elemento seleccionado, de lo contrario, el desplazador de desplazamiento se desplaza hasta el final y el elemento de destino se selecciona en su posición.

Los puntos clave son:

  • Use CollectionView en el lado comercial y habilite la sincronización actual de elementos en el control XAML ( IsSynchronizedWithCurrentItem=true )
  • Postergue el desplazamiento del objetivo "real" para permitir que el "Elemento seleccionado del último" se ejecute en forma visual (utilizando un Dispatcher.BeginInvoke con baja prioridad)

Aquí está la lógica de negocios (Esta es la conversión automática de C # a VB)

Public Class Foo Public Property FooNumber As Integer Get End Get Set End Set End Property End Class Public Class MainWindow Inherits Window Implements INotifyPropertyChanged Private _myCollectionView As ICollectionView Public Sub New() MyBase.New DataContext = Me InitializeComponent MyCollection = New ObservableCollection(Of Foo) MyCollectionView = CollectionViewSource.GetDefaultView(MyCollection) Dim i As Integer = 0 Do While (i < 50) MyCollection.Add(New Foo) i = (i + 1) Loop End Sub Public Property MyCollectionView As ICollectionView Get Return Me._myCollectionView End Get Set Me._myCollectionView = value Me.OnPropertyChanged("MyCollectionView") End Set End Property Private Property MyCollection As ObservableCollection(Of Foo) Get End Get Set End Set End Property Private Sub ButtonBase_OnClick(ByVal sender As Object, ByVal e As RoutedEventArgs) Dim targetNum As Integer = Convert.ToInt32(targetScroll.Text) Dim targetObj As Foo = Me.MyCollection.FirstOrDefault(() => { }, (r.FooNumber = targetNum)) ''THIS IS WHERE THE MAGIC HAPPENS If (Not (targetObj) Is Nothing) Then ''Move to the collection view to the last item Me.MyCollectionView.MoveCurrentToLast ''Bring this last item into the view Dim current = Me.MyCollectionView.CurrentItem itemsContainer.ScrollIntoView(current) ''This is the trick : Invoking the real target item select with a low priority allows previous visual change (scroll to the last item) to be executed Dispatcher.BeginInvoke(DispatcherPriority.ContextIdle, New Action(() => { }, Me.ScrollToTarget(targetObj))) End If End Sub Private Sub ScrollToTarget(ByVal targetObj As Foo) Me.MyCollectionView.MoveCurrentTo(targetObj) itemsContainer.ScrollIntoView(targetObj) End Sub Public Event PropertyChanged As PropertyChangedEventHandler Protected Overridable Sub OnPropertyChanged(ByVal propertyName As String) If (Not (PropertyChanged) Is Nothing) Then PropertyChanged?.Invoke(Me, New PropertyChangedEventArgs(propertyName)) End If End Sub End Class

Y este es el xaml

<Grid> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <DataGrid x:Name="itemsContainer" ItemsSource="{Binding MyCollectionView}" IsSynchronizedWithCurrentItem="True" Margin="2" AutoGenerateColumns="False" > <DataGrid.Columns> <DataGridTextColumn Binding="{Binding FooNumber}"></DataGridTextColumn> </DataGrid.Columns> </DataGrid> <StackPanel Grid.Column="1"> <TextBox x:Name="targetScroll" Text="2" Margin="2"></TextBox> <Button Content="Scroll To item" Click="ButtonBase_OnClick" Margin="2"></Button> </StackPanel> </Grid>


La respuesta aceptada a esta otra pregunta muestra un enfoque diferente para obtener la primera / última fila visible de dicha cuadrícula. Puede encontrar el índice de su fila y desplazarse directamente hacia allí o desplazarse fila por fila hasta que coincida la primera fila visible.


Resolví esta pregunta con el siguiente código:

public partial class MainWindow:Window { private ObservableCollection<Product> products=new ObservableCollection<Product> (); public MainWindow() { InitializeComponent (); for (int i = 0;i < 50;i++) { Product p=new Product { Name="Product "+i.ToString () }; products.Add (p); } lstProduct.ItemsSource=products; } private void lstProduct_SelectionChanged(object sender,SelectionChangedEventArgs e) { products.Move (lstProduct.SelectedIndex,0); lstProduct.ScrollIntoView (lstProduct.SelectedItem); } } public class Product { public string Name { get; set; } } <Grid> <ListBox Name="lstProduct" Margin="20" DisplayMemberPath="Name" SelectionChanged="lstProduct_SelectionChanged" /> </Grid>