2017-04-02 45 views
0

我創建擴展IOrderedIEnumerable 看起來像這樣:爲什麼我遇到內存故障/在UWP/C#應用程序泄漏

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

另外我有一個網頁,它看起來像:

private ObservableCollection<BusStopName> _ListOfBusStopNames; 

public BusStopsListPage() 
{ 
    this.InitializeComponent(); 
    this.SetIsBackFromPageAllowed(true); 

    _ListOfBusStopNames = Timetable.Instance.BusStopsNames 
            .OrderBy(p => p.Name) 
            .ToObservableCollection<BusStopName>(); 
} 

在這個頁面我有一個列表視圖,它具有約束力_ListOfBusStopNames

Timetable.Instance.BusStopsNames有2812個條目。

當我導航到此頁面時,應用程序內存正在增長到無窮大。它看起來像(紅線是那一刻,我導航到該頁面):

enter image description here

在內存快照,我們可以看到,這件事情是使這個問題: enter image description here

我沒有任何想法是什麼。 有沒有人有任何想法?

當我改變實例構造到:

public BusStopsListPage() 
{ 
    this.InitializeComponent(); 
    this.SetIsBackFromPageAllowed(true); 

    _ListOfBusStopNames = new ObservableCollection<BusStopName>(); 
} 

一切工作不錯。另外,當我在此構造函數中手動更改ListTimetable.Instance.BusStopsNames)至ObservableCollection時,它也很棒。

編輯 嗯..我試圖做一個例子如何重現它,我得到了它的解決方案。這是非常混亂,所以如果有人可以解釋爲什麼發生這種情況,將是不錯的:)

  1. 創建UWP APP
  2. 添加在MainPage.xaml中只有這個:<Frame Name="MainFrame" />
  3. 在代碼隱藏地說: this.Loaded += (s, e) => MainFrame.Navigate(typeof(BlankPage1));
  4. 與名BlankPage1
  5. 創建新的空白頁面在BlankPage的景觀補充一點:

    <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> 
    
  6. 在代碼隱藏的說:

    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; } 
        } 
    
  7. 運行應用程序

所以..你可以看到,應用滯後,記憶會採取越來越多。而現在..試圖刪除BlankPage1查看StackPanel。現在運行應用程序。

+0

隨着列表WPF創建一個強大的集合參考。通過使用ObservableCollection – Sybren

+1

修復它我看不出你的圖形如何演示一個問題。它顯示了一個大小約爲100K的對象,與您跟蹤涉及的200MB相差甚遠。值得注意的是,.NET(以及一般的託管系統)往往需要內存。他們可能會從操作系統臨時分配大量內存,然後即使這些對象不在其周圍,請保留分配的內存,以備將其用於其他目的。如果你想得到很好的建議,你需要提供一個可靠地再現問題的良好[mcve]。 –

+0

@PeterDuniho我更新了帖子。請檢查出來 – Niewidzialny

回答

1

這是一個常見問題。問題在於XAML中面板的濫用。 A Grid將伸展以適應其容器的邊界並將其級聯到其子女。 A StackPanel只能級聯反向方向的大小。

例如,當您有<StackPanel Orientation="Vertical"/>時,所有孩子將收到父母Grid的寬度,但不是高度。由於方向是垂直的,所以高度將是無限的,以允許面板根據他們要求的高度疊放它的孩子。

當你有<StackPanel Orientation="Horizontal"/>時,所有的孩子都會收到父母的高度Grid,但不是寬度。與上述相同的原因。它需要水平堆疊。

所以...,當你有一個<ListView/><StackPanel/>

<StackPanel> 
    <ListView>...</ListView> 
</StackPanel> 

StackPanel是告訴ListView渲染與高度=無窮大大小。因此,ListView中的所有2,800個項目實際上都是呈現的,沒有虛擬化。

當方向相同時,您必須避免將ListView放入StackPanel中。

這應該工作:

<Grid> 
    <StackPanel Orientation="Horizontal"> 
     <ListView>...</ListView> 
    </StackPanel> 
</Grid> 

...但它是愚蠢的。

+0

不錯,非常感謝。接下來我學到了:) – Niewidzialny