DataGrid.ScrollIntoView的视图模型中的处理选择更改

问题描述 投票:0回答:1

我有以下视图模型类:

public class ViewModel : INotifyPropertyChanged {
    public event PropertyChangedEventHandler PropertyChanged;

    private bool _isSelected;
    public bool IsSelected {
        get => _isSelected;
        set {
            if (value == _isSelected) { return; }
            _isSelected = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsSelected)));
        }
    }

    public int Data { get; }
    public ViewModel(int data) => Data = data;
}

和以下视图:

<Window x:Class="MVVMScrollIntoView.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <DataGrid Name="dg">
    <DataGrid.RowStyle>
      <Style TargetType="DataGridRow">
        <Setter Property="IsSelected" Value="{Binding IsSelected}"/>
      </Style>
    </DataGrid.RowStyle>
  </DataGrid>
</Window>

我在下面的代码中设置了DataGrid的ItemsSource,如下所示:

var data = Enumerable.Range(1, 100).Select(x => new ViewModel(x)).ToList();
dg.ItemsSource = data;

将数据网格中的选择/取消选择行传播到视图模型实例,并将从代码到视图模型的IsSelected属性的更改传播回数据网格。

但是我希望通过代码设置IsSelected属性时:

data[79].IsSelected = true;

选定的数据网格行也应该滚动到视图中,大概使用数据网格的ScrollIntoView方法。


我最初的想法是在后面的视图代码中侦听SelectionChanged事件:

dg.SelectionChanged += (s, e) => dg.ScrollIntoView(dg.SelectedItem);

但是这不起作用,因为SelectionChanged仅在启用虚拟化时才在可见项目上触发。

关闭虚拟化是一个成功的解决方法:

<DataGrid Name="dg" EnableRowVirtualization="False">
   ...

但是我担心大型列表(超过2万个项目)的性能影响,所以我不希望这样做。


MVVM执行此操作的方式是什么?

c# wpf mvvm datagrid
1个回答
0
投票

如果您不想放弃虚拟化,则可以使用行索引:

private void Button_Click(object sender, RoutedEventArgs e)
{
    var idxToScroll = 4;//e.g. scroll to 4
    var firstItem = listView.ItemContainerGenerator.ContainerFromIndex(0);

    ScrollContentPresenter presenter = null;
    for (var vis = firstItem as UIElement; vis != null; vis = VisualTreeHelper.GetParent(vis) as UIElement)
        if ((presenter = vis as ScrollContentPresenter) != null)
            break;
    if (presenter == null)
        throw new Exception();

    var virtStackPnl = FirstVisualChild(presenter.Content as ItemsPresenter);//VirtualizingStackPanel
    (virtStackPnl as VirtualizingPanel)?.BringIndexIntoViewPublic(idxToScroll);
}
private static DependencyObject FirstVisualChild(UIElement visual)
{
    if (visual == null)
        return null;
    if (VisualTreeHelper.GetChildrenCount(visual) == 0)
        return null;
    return VisualTreeHelper.GetChild(visual, 0);
}
© www.soinside.com 2019 - 2024. All rights reserved.