शीर्ष पर चयनित आइटम को दिखाने के लिए WPF DataGrid को स्क्रॉल करें




vb.net scrollviewer (2)

मेरे पास कई मदों के साथ एक डाटाग्रीड है और मुझे प्रोग्रामित रूप से SelectedItem आईटम तक स्क्रॉल करने की आवश्यकता है I मैंने स्टैक ओवरफ्लो और Google पर खोज की है, और ऐसा लगता है कि समाधान ScrollIntoView है, इस प्रकार है:

grid.ScrollIntoView(grid.SelectedItem)

जो कि डेटाग्रिड को ऊपर या नीचे स्क्रॉल करता है जब तक कि चुने गए आइटम फ़ोकस में नहीं होते हैं। हालांकि, चयनित आइटम के सापेक्ष मौजूदा स्क्रॉल स्थिति के आधार पर, चुने गए आइटम को डेटाग्रिड के स्क्रॉलविवर में अंतिम दृश्यमान आइटम समाप्त हो सकता है। मैं चाहता हूं कि चुने गए आइटम स्क्रॉल विवर में पहली दिखाई वाली वस्तु होगी (यह मानते हुए कि यह अनुमति देने के लिए डेटाग्रीड में पर्याप्त पंक्तियां हैं)। इसलिए मैंने यह कोशिश की:

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

सबसे पहले मैं डेटाग्रीड के अंत तक स्क्रॉल करता हूं और केवल तभी चुने हुए इटैम पर स्क्रॉल कर सकता हूँ, जिस बिंदु पर चयनित आईटैम डाटाग्रिड के शीर्ष पर दिखाया गया है।

मेरी समस्या यह है कि डेटाग्रिड के अंत तक स्क्रॉल करना अच्छी तरह से काम करता है, लेकिन बाद में चुने हुए आइटम को स्क्रॉल करना हमेशा काम नहीं करता है

मैं इस मुद्दे को कैसे सुलझा सकता हूं, या शीर्ष स्थान में एक विशिष्ट रिकॉर्ड पर स्क्रॉल करने के लिए कोई अन्य वैकल्पिक रणनीति है?


आप सही रास्ते पर थे, बस इस तरह की जरूरतों के लिए डेटाग्रिड पर सीधे काम करने के बजाय संग्रह दृश्य के साथ काम करने की कोशिश करें।

यहां एक काम उदाहरण है जहां वांछित वस्तु हमेशा संभवतः पहले चयनित आइटम के रूप में प्रदर्शित होती है, अन्यथा स्क्रॉल-एवरीर को अंत तक स्क्रॉल किया जाता है और लक्ष्य की वस्तु को उसके स्थान पर चुना जाता है।

प्रमुख बिंदु हैं:

  • व्यापार पक्ष पर संग्रह देखें का उपयोग करें और IsSynchronizedWithCurrentItem=true नियंत्रण पर वर्तमान आइटम सिंक को सक्षम करें ( IsSynchronizedWithCurrentItem=true )
  • दृश्य "निष्पादित" दृश्यमान होने के लिए "अंतिम आइटम का चयन करें" की अनुमति देने के लिए "वास्तविक" लक्ष्य स्क्रॉल को हटा दें (कम प्राथमिकता के साथ एक Dispatcher.BeginInvoke का उपयोग करके)

यहां व्यवसाय तर्क है (यह सी # से वीबी के लिए स्वचालित रूपांतरण है)

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

और यह 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>

मैं निम्नलिखित प्रश्न के साथ इस प्रश्न का हल:

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>