代码之家  ›  专栏  ›  技术社区  ›  Kerwen

如何在MVVM中设置datagrid滚动条位置

  •  0
  • Kerwen  · 技术社区  · 8 年前


    由于日志数目很大,我不想在页面初始化时立即加载数据。下面是我的设计:
    在initialize中加载前20行。当用户拖动滚动条时,我将计算滑动条移动的距离,得到日志的索引,然后从服务器检索新的日志。旧日志将被清除,以确保datagrid的内存消耗不太大。
    但在实施过程中,我遇到了以下问题

    2。在拖动滑块(未完成)期间,datagride的内容也将自动更改。我该如何禁用它。 以下是我的代码:

    <DataGrid x:Name="LogsGrid"
              Margin="0,0,0,0"
              Height="457"
              HeadersVisibility="Column" 
              ItemsSource="{Binding LogsList}" 
              SelectedItem="{Binding SelectedRow, Mode=TwoWay}" 
              ScrollViewer.CanContentScroll="True">
    <i:Interaction.Triggers>
        <local:RoutedEventTrigger RoutedEvent="ScrollViewer.ScrollChanged">
            <local:CustomCommandAction Command="{Binding ScrollCommand}" />
        </local:RoutedEventTrigger>
    </i:Interaction.Triggers>
    <DataGrid.Columns>
        ...
    </DataGrid.Columns>
    

    public LogsViewModel()
    {
        InitializeCommand();
        scrollTimer = new DispatcherTimer();
        scrollTimer.Interval = new TimeSpan(0,0,0,0,250);
        scrollTimer.Tick += new EventHandler(ScrollTimer_Elapsed);
    }
    
    private void ScrollTimer_Elapsed(object sender, EventArgs e)
    {
        scrollTimer.Stop();
        GetNewLog(nCurrentScrollIndex);
    }
    
    private int nCurrentScrollIndex = 0;
    private void OnScroll(object param)
    {
        ScrollChangedEventArgs args = param as ScrollChangedEventArgs;
        if (args.VerticalOffset == 0)
        {
            return;
        }
        int nLogTotalNumber = int.Parse(LogTotalNumber);
        nCurrentScrollIndex = (int)(args.VerticalOffset/args.ExtentHeight * nLogTotalNumber);
    
        if (scrollTimer!= null || scrollTimer.IsEnabled)
        {
            scrollTimer.Stop();
        }
        scrollTimer.Start();
    }
    
    1 回复  |  直到 8 年前
        1
  •  1
  •   Mark Feldman    8 年前

    我不认为有必要像这样深入研究WPF的螺母和螺栓。DataGrid支持虚拟化,因此除非您做了一些破坏它的事情,否则它应该只获取屏幕上实际可见的项。也就是说,在不锁定GUI线程的情况下,我永远无法让DataGrid正确地异步获取项,因此您可能需要在视图模型中自己处理这个问题。

    下面是一个在我的i7上轻松管理1000万条记录的示例,我将首先对DataGrid进行模板化:

    <DataGrid ItemsSource="{Binding Items}" AutoGenerateColumns="False">
        <DataGrid.Columns>
            <DataGridTemplateColumn Header="Text">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Text}" />
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
        </DataGrid.Columns>
    </DataGrid>
    

    以下是主视图模型,它创建一个项数组,并仅在请求时获取每个项:

    public class MainViewModel : ViewModelBase
    {
        public Item[] Items { get; }
    
        public MainViewModel()
        {
            this.Items = Enumerable
                .Range(1, 1000)
                .Select(i => new Item { Value = i })
                .ToArray();
        }
    }
    
    public class Item : ViewModelBase
    {
        public int Value { get; set; }
    
        private string _Text;
        public string Text
        {
            get
            {
                // if already loaded then return what we got
                if (!String.IsNullOrEmpty(this._Text))
                    return this._Text;
    
                // otherwise load the value in a task (this will raise property changed event) 
                Task.Run(async () => {
                    Debug.WriteLine($"Fetching value # {Value}");
                    await Task.Delay(1000); // simulate delay in fetching the value
                    this.Text = $"Item # {Value}";
                });
    
                // return default string for now
                return "Loading...";
            }
            set
            {
                if (this._Text != value)
                {
                    this._Text = value;
                    RaisePropertyChanged(() => this.Text);
                }
            }
        }
    
    }
    

    当然,这是一个非常基本的例子,只是为了证明这一点。在现实世界中,您需要建立某种缓存,并一次获取记录块。您可能还需要某种优先级预先考虑好的队列,以预测将来可能获取的记录。不管怎样,WPF都不支持数据虚拟化,所以我认为你必须做这样的事情才能得到你想要的行为。