2016-12-12 1 views
0

Я пишу код, который читает CSV-файл и преобразует его в DateTable. На следующем шаге он читает DataTable для получения конкретных значений. Эти значения были сохранены в объекте, и этот объект добавит в ObserableCollection.Почему число объектов в моем приложении WPF увеличивается?

XAML:

<ListView ItemsSource="{Binding ProdOrderView}" x:Name="listView" Margin="9,70,112,34" AlternationCount="2" FontSize="14"> 
      <ListView.ItemContainerStyle> 
       <Style TargetType="{x:Type ListViewItem}"> 
        <Setter Property="HorizontalContentAlignment" Value="Stretch"/> 
        <Style.Triggers> 
         <Trigger Property="ItemsControl.AlternationIndex" Value="0"> 
          <Setter Property="Background" Value="White" /> 
         </Trigger> 
         <Trigger Property="ItemsControl.AlternationIndex" Value="1"> 
          <Setter Property="Background" Value="LightGray" /> 
         </Trigger> 
        </Style.Triggers> 
       </Style> 
      </ListView.ItemContainerStyle> 
      <ListView.View > 
       <GridView > 
        <GridViewColumn Header="Fauf" Width="Auto"> 
         <GridViewColumn.CellTemplate> 
          <DataTemplate> 
           <TextBlock Text="{Binding Fauf}" TextAlignment="Right" Name="fauf"/> 
          </DataTemplate> 
         </GridViewColumn.CellTemplate> 
        </GridViewColumn> 
        <GridViewColumn Header="Prod-Start" Width="Auto"> 
         <GridViewColumn.CellTemplate> 
          <DataTemplate> 
           <TextBlock Text="{Binding Start}" TextAlignment="Center" Name="start"/> 
          </DataTemplate> 
         </GridViewColumn.CellTemplate> 
        </GridViewColumn> 
        <GridViewColumn Header="Rück- &#xa;stand" Width="Auto"> 
         <GridViewColumn.CellTemplate> 
          <DataTemplate> 
           <TextBlock x:Name="inRueck" Text="{Binding InRueck}" TextAlignment="Center" /> 
           <DataTemplate.Triggers> 
            <DataTrigger Binding="{Binding InRueck, Converter={StaticResource ColorConverterInRueck}}" Value="delay"> 
             <Setter TargetName="inRueck" Property="Background" Value="Red" /> 
            </DataTrigger> 
            <DataTrigger Binding="{Binding InRueck, Converter={StaticResource ColorConverterInRueck}}" Value="inTime"> 
             <Setter TargetName="inRueck" Property="Background" Value="Green" /> 
            </DataTrigger> 
           </DataTemplate.Triggers> 
          </DataTemplate> 
         </GridViewColumn.CellTemplate> 
        </GridViewColumn> 
        <GridViewColumn Header="heute" Width="Auto" > 
         <GridViewColumn.CellTemplate> 
          <DataTemplate> 
           <TextBlock x:Name="Heute" Text="{Binding Heute}" TextAlignment="Center" /> 
           <DataTemplate.Triggers> 
            <DataTrigger Binding="{Binding Heute}" Value="X"> 
             <Setter TargetName="Heute" Property="Background" Value="CornflowerBlue" /> 
            </DataTrigger> 
            <DataTrigger Binding="{Binding Heute}" Value="?"> 
             <Setter TargetName="Heute" Property="Foreground" Value="DarkViolet" /> 
            </DataTrigger> 
           </DataTemplate.Triggers> 
          </DataTemplate> 

         </GridViewColumn.CellTemplate> 
        </GridViewColumn> 
        <GridViewColumn Header="morgen" Width="Auto" > 
         <GridViewColumn.CellTemplate> 
          <DataTemplate> 
           <TextBlock Text="{Binding Morgen}" TextAlignment="Center" Name="Morgen"/> 
          </DataTemplate> 
         </GridViewColumn.CellTemplate> 
        </GridViewColumn> 
        <GridViewColumn Header="+2" Width="Auto" > 
         <GridViewColumn.CellTemplate> 
          <DataTemplate> 
           <TextBlock Text="{Binding Uebermorgen}" TextAlignment="Center" Name="Uebermorgen"/> 
          </DataTemplate> 
         </GridViewColumn.CellTemplate> 
        </GridViewColumn> 
       ... 

       </GridView> 
      </ListView.View> 
     </ListView> 

Code-за:

public MainWindow() 
    { 
     InitializeComponent(); 
     MainViewModel mvm = new MainViewModel(filepath,pline); 
     listView.ItemSource = mvm.ProdOrderView; 
    } 

MainViewModel:

class MainViewModel 
{ 
    #region Private Felder 
    private ObservableCollection<ProductionOrder> _prodOrderList; 

    private ListCollectionView _prodOrderView; 
    #endregion 

    #region Konstruktor 
    public MainViewModel(string filepath, string pline) 
    { 
     // ProductionOrderliste initialisieren 
     _prodOrderList = new ObservableCollection<ProductionOrder>();   

     _prodOrderList.Clear(); 
     fillObject(filepath, pline, ref _prodOrderList); 

     // ListCollectionView initialisieren 
     _prodOrderView = new ListCollectionView(_prodOrderList); 

    } 

    #endregion 

    #region Öffentliche Eigenschaften 
    public ListCollectionView ProdOrderView 
    { 
     get { return _prodOrderView; } 
    } 


    #endregion 

    #region ConvertCSVtoDataTabble 
    public DataTable ConvertCSVtoDataTable(string filename) 
    { 
     //DataTable anlegen 
     DataTable dataTable = new DataTable(); 
     dataTable.Columns.Clear(); 
     dataTable.Rows.Clear(); 
     dataTable.Clear(); 

     try 
     { 
      //Filestream anlegen, dadurch kann Datei auch gelesen werden, wenn sie geöffnet ist 
      FileStream logFileStream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); 

      using (StreamReader streamReader = new StreamReader(logFileStream)) 
      { 
       //Array mit allen Überschriften 
       string[] headers = streamReader.ReadLine().Split(';'); 
       //Schleife durchläuft das Array headers 
       foreach (string header in headers) 
       { 
        //Der DataTable wird eine Spalte mit dem aktuellen header (Überschrift) hinzugefügt. 
        dataTable.Columns.Add(header); 
       } 
       //Schleife, die so lange gültig ist bis das Ende des Streams erreicht wurde 
       while (!streamReader.EndOfStream) 
       { 
        //Array mit allen Zeilen füllen 
        string[] rows = streamReader.ReadLine().Split(';'); 


        //Der DataTable wird die Zeile mit dem aktuellen Werten der Zeile hinzugefügt. 
        dataTable.Rows.Add(rows); 
       } 
       //StreamReader wird geschlossen 
       streamReader.Close(); 
       //Filestream wird geschlossen 
       logFileStream.Close(); 
      } 
     } 
     catch(IndexOutOfRangeException e) 
     { 
      Console.WriteLine("Fehlercode:" + e); 
      ConvertCSVtoDataTable(filename); 
     } 
      //gefüllte DataTable wird zurückgegeben 
      return dataTable; 

     } 

    #endregion 

    #region fillObbject 
    public void fillObject(string filepath, string plinie, ref ObservableCollection<ProductionOrder> liste) 
    { 
     //DataTable res = new DataTable(); 
     //res.Columns.Clear(); 
     //res.Rows.Clear(); 
     //res.Clear(); 


     string emptyField = "\" \""; 
     DataTable res = ConvertCSVtoDataTable(filepath); 
     try 
     { 
      foreach (DataRow row in res.Rows) // Loop over the rows. 
      { 


       if (row["AFKO_PLTXT"].ToString() == plinie) 
       { 

        ////Objekt anlegen 
        ProductionOrder order = new ProductionOrder(); 

        //#region Prüft ob Sammelhinweis vorhanden 
        string sammel = ""; 
        Queue<string> queue = new Queue<string>(); 

        if (res.Columns.Contains("ZZTAG_MO")) 
        { 
         //Montag 
         if (row["ZZTAG_MO"].ToString() == "X") 
         { 
          sammel = "MO"; 
          queue.Enqueue(sammel); 
         } 
         //Dienstag 
         if (row["ZZTAG_DI"].ToString() == "X") 
         { 
          sammel = "DI"; 
          queue.Enqueue(sammel); 
         } 
         //Mittwoch 
         if (row["ZZTAG_MI"].ToString() == "X") 
         { 
          sammel = "MI"; 
          queue.Enqueue(sammel); 
         } 
         //Donnerstag 
         if (row["ZZTAG_DO"].ToString() == "X") 
         { 
          sammel = "DO"; 
          queue.Enqueue(sammel); 
         } 
         //Freitag 
         if (row["ZZTAG_FR"].ToString() == "X") 
         { 
          sammel = "FR"; 
          queue.Enqueue(sammel); 
         } 
         //Samstag 
         if (row["ZZTAG_SA"].ToString() == "X") 
         { 
          sammel = "SA"; 
          queue.Enqueue(sammel); 
         } 
         //Sonntag 
         if (row["ZZTAG_SO"].ToString() == "X") 
         { 
          sammel = "SO"; 
          queue.Enqueue(sammel); 
         } 


        } 
        // string sammelList wird zusammengesetzt 
        string sammelList = ""; 
        if (queue.Count > 0) 
        { 
         sammelList = "/"; 
         while (queue.Count > 0) 
         { 
          if (queue.Count > 1) 
           sammelList += queue.Dequeue() + "+"; 
          else 
          { 
           sammelList += queue.Dequeue(); 
          } 
         } 
        } 
        #endregion 
        //das Objekt wird mit den entsprechenden Werten gefüllt 
        order.Fauf = row["EXTRA_APO"].ToString(); 
        order.Start = row["GSTRP_KO"].ToString(); 
        order.Vorgang = row["LTXA1_AFVC"].ToString(); 
        order.Kundenauftrag = row["KDAUF_FK"].ToString() + sammelList; 
        order.Material = row["MATNR_PO"].ToString(); 
        order.Materialbezeichnung = row["MAKTX_MAKT"].ToString(); 
        order.Menge = row["AFKO_GAMNG"].ToString(); 
        order.WE_Menge = row["WEMNG_PO"].ToString(); 
        order.Ende = row["GLTRP_KO"].ToString(); 
        order.Notiz = row["NOTIZ_TEXT"].ToString(); 
        order.Ladedatum = row["LDDAT_VBEP"].ToString(); 
        order.Dauer = row["FAUFDAUER_REST_KO"].ToString(); 

        //führende Nullen werden entfernt falls vorhanden 
        order.Kundenauftrag = order.Kundenauftrag.TrimStart('0'); 
        order.Material = order.Material.TrimStart('0'); 

        if (order.Menge.Contains(",")) 
        { 
         order.Menge = order.Menge.Remove(order.Menge.IndexOf(@",")); 
        } 
        if (order.WE_Menge.Contains(",")) 
        { 
         order.WE_Menge = order.WE_Menge.Remove(order.WE_Menge.IndexOf(@",")); 
        } 
        order.Heute = ""; 
        order.Morgen = ""; 
        order.Uebermorgen = ""; 
        order.Plus3 = ""; 
        order.Plus4 = ""; 
        order.Plus5 = ""; 

        string inKlaerung = ""; 

        //konvertiert String zu Datetime 
        DateTime newStartDate = convertDateTime(order.Start); 
        order.Start = newStartDate.ToString("dd.MM.yyyy"); 


        //Berechne Verzug in Tagen 
        int verzugTage = (DateTime.Today - newStartDate).Days; 
        order.InRueck = verzugTage.ToString(); 

        //konvertiert String zu Datetime 
        var newLadedatum = convertDateTime(order.Ladedatum); 
        order.Ladedatum = newLadedatum.ToString("dd.MM.yyyy"); 
        if (inKlaerung != emptyField) 
        { 
         //X in der Spalte setzen, an dem Tag wo es gefertigt wird 
         if (verzugTage >= 0) 
         { 
          order.Heute = "X"; 
         } 
         else 
         { 
          switch (verzugTage) 
          { 
           case -1: 
            order.Morgen = "X"; 
            break; 
           case -2: 
            order.Uebermorgen = "X"; 
            break; 
           case -3: 
            order.Plus3 = "X"; 
            break; 
           case -4: 
            order.Plus4 = "X"; 
            break; 
           case -5: 
            order.Plus5 = "X"; 
            break; 
           default: 
            break; 
          } 

         } 
        } 
        else 
        { 
         order.Heute = "?"; 
        } 
        try 
        { 
         //konvertiert String zu Datetime 
         var newEndDate = convertDateTime(order.Ende); 
         order.Ende = newEndDate.ToString("dd.MM.yyyy"); 
        } 
        catch (FormatException e) 
        { 
         Console.WriteLine("Fehlercode:" + e); 
         order.Ende = "Fehler"; 
        } 

        // Prüft ob Vorgang leer ist 
        if (order.Vorgang == emptyField) 
        { 
         order.Vorgang = ""; 
        } 

        //Prüft ob Notiz leer ist 
        if (order.Notiz == emptyField) 
        { 
         order.Notiz = ""; 
        } 

        //Prüft ob Dauer leer ist 
        if (order.Dauer == emptyField) 
        { 
         order.Dauer = ""; 
        } 


        liste.Add(order);            
       } 
      }    
     } 

     catch (ArgumentException e) 
     { 

      Console.WriteLine("Fehlercode:" + e); 
     } 

    } 
    // #endregion 

    #region convertDateTime 
    public DateTime convertDateTime(string date) 
    { 
     //konvertiert String zu Datetime 
     DateTime newDate = DateTime.ParseExact(date, 
        "yyyyMMdd", 
         System.Globalization.CultureInfo.InvariantCulture); 
     return newDate; 

    } 
    #endregion 
} 
} 

Когда я загружаю CSV файл каждую минуту количество объектов будет extreamly увеличиваться. Сборщик мусора не очищает все старые объекты. может ли кто-нибудь помочь мне найти эту проблему?

+0

всегда будет некоторое увеличение, как вы загружаете больше данных в коде, но это должен быть линейный рост по отношению к данным – MikeT

+0

Даже если это всегда тот же файл? – Nesslae

+0

, если вы загружаете новые данные, тогда да, после того, как загрузка будет завершена, GC очистит объекты, которые больше не используются, которые, если вы используете ресурсы выпуска, должны снова вернуть вас обратно.также помните, что wpf использует, по возможности, ленивую загрузку, если вы загружаете 5000 предметов в сетку, тогда она будет загружать только те, которые на самом деле видны на экране, так как вы перемещаетесь по списку, будут загружены новые элементы, если они не будут очень сложный это лучший способ сделать это – MikeT

ответ

0

Я предполагаю, что ваша проблема заключается в том, что вы используете таблицы данных, в которых вам не нужно.

DataTable - очень сложный элемент, который в основном представляет собой таблицу базы данных, основанной на кодах, и из-за этого используется MarshalByValueComponent, в котором говорится, что это не может быть автоматически GC'ed, и поэтому необходимо вызвать Dispose после того, как вы закончили использовать его. (вызов Dispose указывает ему очистить свои ссылки от неуправляемого кода и быть доступным сборщику мусора).

у вас есть 2 варианта для запуска удаления простого вызова к Dispose функции или с помощью() {} о

вам нужно сделать, это для всех классов, которые являются неуправляемыми (включая StreamReader & FileStream)

как вы не используете таблицу данных как DataTable, просто стол, то я бы предложил удалить его полностью и просто разборе текстовый файл вместо

EDIT:

Здесь S быстрая и грязная модель для MVVM файла парсер

XAML: за

<Window x:Class="WpfApplication1.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:local="clr-namespace:WpfApplication1" 
     mc:Ignorable="d" 
     Title="MainWindow" Height="350" Width="525"> 
    <Window.DataContext> 
     <local:FileViewModel x:Name="vm" /> 
    </Window.DataContext> 

    <DockPanel > 
     <DockPanel DockPanel.Dock="Top"> 
      <Button DockPanel.Dock="Right" Click="Button_Click">Read</Button> 
      <TextBox Text="{Binding File}" /> 
     </DockPanel> 
     <ListView ItemsSource="{Binding ItemCollection}"> 
      <ListView.View> 
       <GridView> 
        <GridViewColumn DisplayMemberBinding="{Binding field1}" Header="Feild1"/> 
        <GridViewColumn DisplayMemberBinding="{Binding field2}" Header="Field2"/> 
        <GridViewColumn DisplayMemberBinding="{Binding field3}" Header="Field3"/> 
        <GridViewColumn DisplayMemberBinding="{Binding field4}" Header="Field4"/> 
       </GridView> 
      </ListView.View> 

     </ListView> 
    </DockPanel> 
</Window> 

Кода:

чтение файла

public class FileViewModel : INotifyPropertyChanged 
{ 
    private string _File; 

    public string File 
    { 
     get { return _File; } 
     set 
     { 
      _File = value; 
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("File")); 
     } 
    } 

    public ObservableCollection<ItemModel> ItemCollection { get; } = new ObservableCollection<ItemModel>(); 

    public event PropertyChangedEventHandler PropertyChanged; 

    public void ReadFile() 
    { 
     ItemCollection.Clear(); 

     using (StreamReader reader = new StreamReader(File)) 
     { 
      var header = reader.ReadLine(); 
      while(!reader.EndOfStream) 
      { 
       var data = reader.ReadLine(); 
       var item = ItemModel.Create(header, data, ','); 
       ItemCollection.Add(item); 
      } 
     } 
    } 
} 

Item Parser

public class ItemModel 
{ 
    public static ItemModel Create(string colstr, string datastr, char delimiter) 
    { 
     var cols = colstr.Split(delimiter); 
     var data = datastr.Split(delimiter); 

     var item = new ItemModel(); 

     item.field1 = int.Parse(GetValue(cols, data, "field1")); 
     item.field2 = DateTime.Parse(GetValue(cols, data, "field2")); 
     item.field3 = GetValue(cols, data, "field3"); 
     item.field4 = double.Parse(GetValue(cols, data, "field4")); 
     return item; 
    } 
    public static string GetValue(string[] cols, string[] data, string colName) 
    { 
     var colid = Array.IndexOf(cols, colName); 
     if (colid == -1) 
      return null; 
     else 
      return data[colid]; 
    } 

    public int field1 { get; set; } 
    public DateTime field2 { get; set; } 
    public string field3 { get; set; } 
    public double field4 { get; set; } 

} 

Demo Файл используется

field2,field1,field4,field3 
01-Jan-16,1,1.1,a 
02-Jan-16,2,2.2,b 
03-Jan-16,3,3.3,c 
04-Jan-16,4,4.4,d 
+0

Спасибо за ваш ответ. Но причина, по которой я использую DataTable, заключается в том, что CSV имеет 850 столбцов. И мне просто нужно ок. 20. Другим преимуществом является то, что я могу получить значение из этих столбцов с именем столбца, поэтому он не зависит от порядка столбцов. У вас есть предложение, как я могу прочитать значение с именем столбца? – Nesslae

+0

см. Пример, который я добавил в ответ – MikeT

Смежные вопросы