WPF CollectionView / DataGrid получить индекс первого видимого элемента - PullRequest
0 голосов
/ 12 декабря 2018

есть ли способ получить первый видимый элемент, который отображается пользователю?

В WinForms DatagridView у нас было FirstDisplayedScrollingRowIndex.Есть ли эквивалент для варианта WPF?

Я использую CollectionView в моем ViewModel, который связан с DataGrid в XAML.

Просто чтобы прояснить: Я не хочу получить индекс SelectedRow, это я уже могу сделать ...

Пример
У меня естьполучил 20 элементов в моей коллекции ObservableCollection, и моя таблица данных может показывать только 13 из-за ограничений по размеру.Item2 был ранее выбран пользователем, и после этого пользователь немного прокрутил его, поэтому элементы 5-17 видны.Как получить индекс item5?

XAML

<Style x:Key="DatagridStyle" TargetType="DataGrid">
        <Setter Property="AutoGenerateColumns" Value="False"/>
        <Setter Property="Background" Value="{StaticResource ColorDatagridBackground}"/>
        <Setter Property="IsReadOnly" Value="True"/>
        <Setter Property="CanUserAddRows" Value="False"/>
        <Setter Property="CanUserDeleteRows" Value="False"/>
        <Setter Property="CanUserResizeColumns" Value="False"/>
        <Setter Property="CanUserReorderColumns" Value="True"/>
        <Setter Property="CanUserSortColumns" Value="True"/>
        <Setter Property="ColumnHeaderHeight" Value="25"/>
        <Setter Property="Margin" Value="0,5,0,5"/>
        <Setter Property="ItemsSource" Value="{Binding ItemCollection}"/>
</Style>
<DataGrid DockPanel.Dock="Top" 
              Style="{StaticResource DatagridStyle}"
              util:DataGridColumnsBehavior.BindableColumns="{Binding DatagridColumns, UpdateSourceTrigger=PropertyChanged}"
              IsSynchronizedWithCurrentItem="True"
              EnableRowVirtualization="True">
        <i:Interaction.Behaviors>
            <util:DataGridScrollBehaviour />
        </i:Interaction.Behaviors>
</DataGrid>

ViewModel

private ObservableCollection<DataGridColumn> _datagridColumns;
private CollectionView _itemCollection;
private CollectionViewSource _itemCollectionSource;
public ObservableCollection<DataGridColumn> DatagridColumns
    {
        get => _datagridColumns;
        set
        {
            _datagridColumns = value;
            RaisePropertyChanged();
        }
    }
    public CollectionView ItemCollection
    {
        get => _itemCollection;
        set
        {
            _itemCollection = value;
            RaisePropertyChanged();
        }
    }
    public CollectionViewSource ItemCollectionSource
    {
        get => _itemCollectionSource;
        set
        {
            _itemCollectionSource = value;
            RaisePropertyChanged();
        }
    }


    _datagridColumns = MainViewModel.GetColumns(MainViewModel.AppMode.Match);

    _itemCollectionSource = new CollectionViewSource();
    ItemCollectionSource.Source = _vml.Main.ItemList;
    _itemCollection = (CollectionView)ItemCollectionSource.View;

Желаемый результат: , если моя область просмотра ...
- в top , и я добавляю элемент сверху (из-за текущей сортировки), я хочу, чтобы моя область просмотра былаоставайтесь наверху, чтобы я мог видеть свой новый элемент
- в внизу и добавлял элемент внизу (из-за текущей сортировки), я хочу, чтобы моя область просмотра переместилась в«новое» дно, поэтому я могу видеть мой новый элемент
- где-то посередине, я хочу продолжать смотреть на те же элементы X

Я могу получить доступ к SortOrder через мой CollectionView, но для того, чтобычтобы определить, где моя область обзора должна быть перемещена, мне нужно знать, где находится моя область обзора в данный момент (верхняя, средняя, ​​нижняя)

Ответы [ 2 ]

0 голосов
/ 31 декабря 2018

Для моей проблемы (просмотрщик прокрутки с элементом управления элементами) я обнаружил, что решение состоит в том, чтобы захватить событие изменения прокрутки и использовать его.Поскольку в DataGrid есть средство просмотра с прокруткой, я думаю, что вы можете сделать то же самое, или вместо измененной прокрутки использовать ту же логику в другом месте, что наиболее целесообразно.Таким образом, в коде окна:

    private void dgScrollChanged(object sender, ScrollChangedEventArgs e)
    {
        int i = 0;
        DataGrid dg = (DataGrid)sender;
        foreach (ObservableFlatObservations o in dg.Items)
        {
            UIElement v = (UIElement)dg.ItemContainerGenerator.ContainerFromItem(o);
            GeneralTransform childTransform = v.TransformToAncestor((ScrollViewer)sender);
            Rect rectangle = childTransform.TransformBounds(new Rect(new Point(0, 0), v.RenderSize));
            Rect result = Rect.Intersect(new Rect(new Point(0, 0), ((ScrollViewer)sender).RenderSize), rectangle);
            if (result != Rect.Empty)
            {
                //This one is visible so do some stuff
                return;// i is the index of this item
            }
            i++;
        }
    }

И в определении xaml таблицы данных:

<DataGrid x:Name="MainDataGrid" AutoGenerateColumns="False" HorizontalAlignment="Stretch" Margin="0,0,0,0" VerticalAlignment="Stretch"
          ItemsSource="{Binding oFObs.View}"
          SelectedItem="{Binding CurrentObs, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
          IsReadOnly="True"
          Grid.Row="1" Grid.ColumnSpan="3"
          ScrollViewer.ScrollChanged="dgScrollChanged">

Я еще не проверял это с моей сеткой данных, но этот метод хорошо работал длямой оригинальный случай.Обратите внимание, что мои имена элементов данных не соответствуют вашему вопросу, но я думаю, что вы можете изменить это, чтобы работать с тем, что у вас есть.В обработчике событий только строки, видимые в сетке, будут возвращать значение из вызова ContainerFromItem, потому что сетка данных виртуализирует содержимое.Поэтому я думаю, что если вы сделаете что-то подобное, вы можете найти первый видимый индекс в сетке данных:

private void dgScrollChanged(object sender, ScrollChangedEventArgs e)
{
    int i = 0;
    DataGrid dg = (DataGrid)sender;
    foreach (GetFlatObservationsResult o in dg.ItemsSource)
    {
        DataGridRow v = (DataGridRow)dg.ItemContainerGenerator.ContainerFromItem(o);
        if(v!=null)
        {
            //i is the index of the first visable row
            //do some stuff
            return;
        }
        i++;
    }
}
0 голосов
/ 12 декабря 2018

вы можете добавить атрибут SelectedIndex="{Binding SelIndex}" в тег коллекции.

Где SelIndex будет свойством в вашем файле ViewModel, привязанном к этому атрибуту.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...