Reputation: 340
I created extension to IOrderedIEnumerable
which looks like this:
internal static ObservableCollection<T> ToObservableCollection<T>(this IOrderedEnumerable<T> list)
{
var observableCollection = new ObservableCollection<T>();
foreach (var p in list)
observableCollection.Add(p);
return observableCollection;
}
Also I have a page which looks like:
private ObservableCollection<BusStopName> _ListOfBusStopNames;
public BusStopsListPage()
{
this.InitializeComponent();
this.SetIsBackFromPageAllowed(true);
_ListOfBusStopNames = Timetable.Instance.BusStopsNames
.OrderBy(p => p.Name)
.ToObservableCollection<BusStopName>();
}
And in this page i have a listview which has binding to _ListOfBusStopNames
Timetable.Instance.BusStopsNames
has 2812 entries.
When I'm navigating to this page, application memory is growing up to infinity numbers. It looks like (red line is moment when I navigated to this page):
In memory snapshot we can see that this thing is making this problem:
I don't have any idea what it can be. Do anyone have any idea?
When I change instance constructor to:
public BusStopsListPage()
{
this.InitializeComponent();
this.SetIsBackFromPageAllowed(true);
_ListOfBusStopNames = new ObservableCollection<BusStopName>();
}
everything works nice. Also, when I changed in this constructor manually List
( Timetable.Instance.BusStopsNames
) to ObservableCollection
, it works great too.
EDIT Hm.. i tried to make an example how to reproduce it, and i get to a solution for it. It is very confusing, so if someone can explain why this is happening it will be nice :)
<Frame Name="MainFrame" />
this.Loaded += (s, e) => MainFrame.Navigate(typeof(BlankPage1));
BlankPage1
In View of BlankPage add this:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel>
<ListView ItemsSource="{x:Bind _ListOfTestClasses}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:TestClass">
<Grid>
<TextBlock Text="{x:Bind Name}" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</Grid>
In code-behind put:
public sealed partial class BlankPage1 : Page
{
private List<TestClass> _List;
private ObservableCollection<TestClass> _ListOfTestClasses;
public BlankPage1() {
this.InitializeComponent();
GenerateTestData();
_ListOfTestClasses = _List.OrderBy(p => p.Name).ToObservableCollection<TestClass>();
}
private void GenerateTestData() {
_List = new List<TestClass>();
for(int i = 0; i < 2800; i++)
_List.Add(new TestClass() { Id = i, Name = Guid.NewGuid().ToString() });
}
}
public static class Extension {
public static ObservableCollection<T> ToObservableCollection<T>(this IOrderedEnumerable<T> list) {
var observableCollection = new ObservableCollection<T>();
foreach (var p in list)
observableCollection.Add(p);
return observableCollection;
}
}
public class TestClass {
public int Id { get; set; }
public string Name { get; set; }
}
Run the app
So.. you can see that app is lagging and memory is going taking more and more.. And now.. try to delete in BlankPage1
view StackPanel
. And now run the app.
Upvotes: 1
Views: 434
Reputation: 6091
This is a common problem. The issue is the misuse of panels in XAML. A Grid
will stretch to fit its container's boundaries and cascade this to its children. A StackPanel
will only cascade the size of the opposing orientation.
For example, when you have <StackPanel Orientation="Vertical"/>
, all children will receive the width of the parent Grid
, but not the height. Because the orientation is vertical, the height will be infinite to allow the panel to stack its children based on their requested heights.
When you have <StackPanel Orientation="Horizontal"/>
, all children will receive the height of the parent Grid
, but not the width. Same reason as above. It needs to stack horizontally.
So..., when you have a <ListView/>
inside a <StackPanel/>
:
<StackPanel>
<ListView>...</ListView>
</StackPanel>
The StackPanel
is telling the ListView
to render its size with height = infinity. And therefore, all 2,800 items in your ListView
are actually being rendered, not virtualized.
You have to avoid putting ListViews in StackPanels when the orientations are the same.
This should work:
<Grid>
<StackPanel Orientation="Horizontal">
<ListView>...</ListView>
</StackPanel>
</Grid>
... but it's silly.
Upvotes: 2