How to set datagrid scrollbar location in MVVM

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP



How to set datagrid scrollbar location in MVVM



I have a datagrid used to display the log information which read from a data server.

As the log number is huge, I don't want to load data at once when page initialize. So below is my design:

Load the first 20 lines in initialize. When user drag the scrollbar, I will calculate the distance which the slider moved, get the index of log and then retrieve new log from server. The old log will be cleared to make sure the datagrid's memory consumption is not large.

But during implement, I met following problem

1. How to set the size of slider? If I only add 20 lines to datagrid, the slider is very long

2. During I drag the slider(not complete), the content of datagride will also change automatically. How should I disable it.
Below is my code:


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





Blew is my viewmodel:


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)




1 Answer
1



I don't think it's necessary going into the nuts-n-bolts of WPF like this. DataGrid supports virtualization, so unless you've done something to break it it should only fetch the items actually visible on-screen. That said, I've never been able to get DataGrid to properly fetch items asynchronously without locking up the GUI thread, so you'll probably have to handle this yourself in the view model.



Here's an example that easily manages 10 million records on my i7, I'll start by templating the 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>



Here's the main view model, which creates an array of items and fetching each one only when requested:


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







This is a very basic example of course, shown only to demonstrate the point. In the real world you would want to set up some kind of cache, and fetch blocks of records at a time. You'd probably also want some kind of prioritized pre-meditated queuing that anticipates records likely to be fetched in future. Either way, WPF doesn't support data virtualization, so I think you're going to have to wind up doing something like this to get the exact behavior you're after.





Thanks Mark. "DataGrid supports virtualization, so unless you've done something to break it it should only fetch the items actually visible on-screen." This really helps me a lot.
– Kerwen
Aug 13 at 5:48





Always double-check it though, because it's very easy to break. Looking at the debug output in my example above will show which items are being fetched, or you can put a breakpoint in your code, add `App.Current.MainWindow' to your watch window and click on the little magnifying glass (i.e. the WPF Tree Visualizer). This lets you browse the graphical items that have been created, so you'll see right away whether or not your visualization is working.
– Mark Feldman
Aug 13 at 6:03







By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Firebase Auth - with Email and Password - Check user already registered

Dynamically update html content plain JS

How to determine optimal route across keyboard