How to lazy-evaluate a wpf:DataGrid, retrieving data only as needed

末鹿安然 提交于 2019-12-12 14:41:24

问题


I have a WPF datagrid, bound to a list populated by linq-to-sql from a database. The binding is two-Way, allowing the user to change the values in each row

        <wpf:DataGrid AutoGenerateColumns="False" 
              ItemsSource="{Binding MyList}" 
              SelectedItem="{Binding SelectedItem}" >

When displaying about 20000 rows, the program crashes with an out-of-memory exception during initialisation of the list. Performance becomes unbearably slow even with less rows.

I know that on initialization the datagrid iterates through each row to measure the maximum column width and other properties. It will apparently do so for all rows regardeless of whether they are on screen.

I tried either binding the datagrid to myQuery.ToList() (to allow sorting the datagrid by clicking on the columns) or binding directly to the IQueryable. (Sorting does not work with that)

Both produce the same result. The ToList() with 20000 items alone does not cause the massive memory consumption, this happens only when it is bound to the datagrid .

Ignoring the issue of how useful 20000 rows in a datagrid are (those are the current requirements; to change those a working example would be helpful).

What is the most simple way to lazily load only the data currently shown on the screen, and ignore everything else until it is scrolled into view?

Can this be done without third party libraries and major code changes?

If not, what would be the recommended workaround?


回答1:


It turns out that the problem was entirely user error on my part:

WPF Datagrid can do UI virtualisation just fine: The memory consuming row objects are only drawn when required; if a row is outside the visible bounds of the datagrid, it will not be instantiated.

This will however not work if the datagrid is contained inside a ScrollViewer. Inside a scrollviewer every part of the datagrid is virtually visible, so the entire datagrid will be rendered. The scrollviewer then shows only the part of this rendered datagrid that fits inside the UI window.

Since a datagrid inside a scrollviewer looks just like a datagrid that manages its own scrollbars, I did not notice the scrollviewer.

With the scrollviewer removed, large amounts of rows cause no problem at all, even with variable height and width. The datagrid simply fills the available space, and only instantiates new rows as required.

So in short, the solution for my problem was: Do not put a datagrid inside a scrollviewer




回答2:


The property that you are binding in this his case let's say that your MyList is made up of MyFile objects (List<MyFile>) then you have to create your MyFile class as:

 class MyFile
    {
        public string FullPath { get; set; }

        public string Extension
        {
            get
            {
                return Path.GetExtension(FullPath);
            }
        }

        public string PathRoot
        {
            get
            {
                return Path.GetPathRoot(FullPath);
            }
        }

        public DateTime CreationTime
        {
            get
            {
                return File.GetCreationTime(FullPath);
            }
        }

    }

That way you will store less info in each object and jut call the get method on the few items that are displayed in the grid. Versus having the actual values stored in the class. Hope this helps



来源:https://stackoverflow.com/questions/10422592/how-to-lazy-evaluate-a-wpfdatagrid-retrieving-data-only-as-needed

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!