2016-12-28 6 views
10

ausgewählte Element zu zeigen, habe ich ein Datagrid mit vielen Elementen und ich muss programmatisch auf die SelectedItem blättern. Ich habe auf Stackoverflow und Google durchsucht, und es scheint, die Lösung ScrollIntoView ist, wie folgt:Scroll WPF Datagrid auf

grid.ScrollIntoView(grid.SelectedItem) 

, die das Datagrid nach oben oder unten scrollt, bis das ausgewählte Element im Fokus ist. Jedoch kann abhängig von der aktuellen Bildlaufposition relativ zu dem ausgewählten Elemente kann das ausgewählte Element ist, das letzte sichtbare Element in der Scroll des Datenraster enden. Ich mag, dass das ausgewählte Element das erste sichtbare Element in der Scroll sein (vorausgesetzt, es gibt genügend Zeilen im Datagrid dies zu ermöglichen). Also habe ich versucht, dies:

'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) 

Zuerst habe ich scrollen bis zum Ende des Datagrid und erst dann blättere ich in die SelectedItem, an welchem ​​Punkt der SelectedItem an der Spitze des Datagrid angezeigt wird.

Mein Problem ist, dass das Scrollen bis zum Ende des DataGrid gut funktioniert, aber das anschließende Scrollen zum ausgewählten Element funktioniert nicht immer.

Wie kann ich dieses Problem lösen, oder gibt es eine andere alternative Strategie für das Scrollen zu einem bestimmten Datensatz in der obersten Position?

Antwort

3

Die akzeptierte Antwort auf this other question zeigt einen anderen Ansatz, um die erste/letzte sichtbare Reihe eines solchen Gitters zu erhalten. Sie könnten den Index Ihrer Reihe herausfinden und direkt dort bewegen oder bis die erste sichtbare Zeile Streichhölzer zeilen nach unten scrollen.

5

Sie waren auf dem richtigen Weg, nur versuchen, anstatt mit der Sammlung Ansicht arbeitet für diese Art von Bedarf direkt auf dem Datenraster zu arbeiten.

Hier ist ein Arbeitsbeispiel, wo der gewünschte Artikel immer als erster ausgewählter Artikel angezeigt wird, ansonsten wird der Scrollviewer zum Ende gescrollt und der Zielartikel an seiner Position ausgewählt.

Die wichtigsten Punkte sind:

  • Verwenden Collection auf der Business-Seite und ermöglichen aktuelle Element Synch auf der XAML-Steuerung (IsSynchronizedWithCurrentItem=true)
  • Aufschieben der „echten“ Ziel blättern, um die „Select zu ermöglichen Letzter Punkt“visualy ausgeführt werden (durch eine Dispatcher.BeginInvoke mit niedriger Priorität verwendet)

Hier ist die Business-Logik (Dies ist eine maschinelle convertion von C# 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 

Und das ist die 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> 
3

ich mit folgendem Code diese Frage gelöst:

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>