繁体   English   中英

WPF CollectionView / DataGrid获取第一个可见项的索引

[英]WPF CollectionView/DataGrid get index of first visible item

有没有办法获取显示给用户的第一个可见项目?

在WinForms的DatagridView我们具有FirstDisplayedScrollingRowIndex WPF变体是否等效?

我在ViewModel中使用了CollectionView,该View绑定到XAML中的DataGrid。

只是要清楚:不想让SelectedRow的指数,这个我已经可以做...


我的ObservableCollection中有20个项目,由于大小限制,我的Datagrid仅显示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>

视图模型

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;

期望的结果:如果我的视野是...
-在顶部,并在顶部添加一个项目(由于当前排序),我希望我的视图区域保持在顶部,这样我就可以看到我的新项目
-在底部,并在底部添加一个项目(由于当前排序),我希望将视图区域移至“新”底部,这样我就可以看到我的新项目
-在中间的任何地方,我想继续查看相同的X件商品

我可以通过CollectionView访问SortOrder,但是为了确定我的视图区域需要移动的位置,我确实需要知道我的视图区域当前的位置(顶部,中间,底部)

对于我的问题(带有项目控件的scrollviewer),我发现解决方案是捕获滚动更改事件并使用它。 由于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++;
        }
    }

在datagrid 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">

我尚未使用datagrid对此进行过测试,但是这种方法在我的原始案例中效果很好。 请注意,我的数据元素名称未映射到您的问题,但是我认为您可以对其进行修改以使用您所拥有的名称。

经过实际尝试,事实证明可能更简单。 在事件处理程序中,只有网格中可见的行才会从ContainerFromItem调用返回值,因为datagrid会虚拟化内容。 因此,我认为如果您执行以下操作,则可以在数据网格中找到第一个可见索引:

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

您可以在集合标记中添加SelectedIndex="{Binding SelIndex}"属性。

其中SelIndex将是ViewModel文件中与此属性绑定的属性。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM