2016-04-21 71 views
2

讓我開始說我是UWP的全新產品,最接近這種語言的是我12年前的C++!UWP 10 C#。將文本文件讀入一個List <>

我正在爲Windows Universal編寫一個應用程序,並且它將逐行閱讀不同的文本文件,拆分每行的內容(某些文件不需要拆分行),添加將數據放入列表中,然後在屏幕上顯示。我已經嘗試了很多方法來做到這一點,但我沒有正確地工作。我目前有兩種方法正在工作,但並不一致。它會顯示數據,但只是有時。當我運行應用程序(在仿真器或本地設備上)時,它可能會或可能不會顯示數據,然後如果我點擊不同的頁面並回到列表頁面,它可能會或可能不會再次顯示它..

下面的代碼。在這種情況下,我拆分文本文件的內容分爲3個字符串分割上的「 - 」

我XAML.cs

文件

public sealed partial class SPList : Page 
{ 
    private List<ThreeColumnList> ThreeColumnLists; 
    public SPList() 
    { 
     this.InitializeComponent(); 
     ThreeColumnLists = ThreeColumnListManager.GetList(); 
    } 
} 

在我的XAML

<Page 
    x:Class="TrackingAssistant.SPList" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="using:TrackingAssistant" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:data="using:TrackingAssistant.Model" 
    mc:Ignorable="d"> 
    <Page.Resources> 
     <!-- x:DataType="<Name Of Class>" --> 
     <DataTemplate x:Key="ThreeColumnListDataTemplate" x:DataType="data:ThreeColumnList"> 
      <StackPanel Orientation="Horizontal" HorizontalAlignment="Left"> 
       <TextBlock Grid.Column="0" Text="{x:Bind Name}" HorizontalAlignment="Left" FontSize="16" Margin="20,20,20,20" /> 
       <TextBlock Grid.Column="1" Text="{x:Bind Age}" HorizontalAlignment="Left" FontSize="16" Margin="20,20,20,20" /> 
       <TextBlock Grid.Column="2" Text="{x:Bind Job}" HorizontalAlignment="Right" FontSize="16" Margin="20,20,20,20" /> 
      </StackPanel> 
     </DataTemplate> 
    </Page.Resources> 

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> 

     <Grid.RowDefinitions> 
      <RowDefinition Height="*" /> 
      <RowDefinition Height="100" /> 
     </Grid.RowDefinitions> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="2*" /> 
      <ColumnDefinition Width="*" /> 
      <ColumnDefinition Width="*" /> 

     </Grid.ColumnDefinitions> 
     <TextBlock Grid.Row="1" 
        Name="ResultTextBlock" 
        FontSize="24" 
        Foreground="Red" 
        FontWeight="Bold" 
        Margin="20,20,0,0" /> 
     <!-- ItemsSource="x:Bind <Variable from the CS(Code) Class> --> 
     <ListView Grid.ColumnSpan="3" ItemsSource="{x:Bind ThreeColumnLists}" 
        ItemTemplate="{StaticResource ThreeColumnListDataTemplate}"> 
     </ListView> 

    </Grid> 
</Page> 
在ThreeColumnList.cs
class ThreeColumnList 
{ 
    public string Name { get; set; } 
    public string Age { get; set; } 
    public string Job { get; set; } 
} 

在我ThreeColumnListManager.cs

class ThreeColumnListManager 
{ 
    public static List<ThreeColumnList> GetList() 
    { 
     var threecolumnlists = new List<ThreeColumnList>(); 

     //Add a dummy row to present something on screen 
     threecolumnlists.Add(new ThreeColumnList { Name = "Name1", Age = "Age1", Job = "Job1" }); 

     //First working method 
     readList(threecolumnlists); 

     //Second Working Method 
     //tryAgain(threecolumnlists); 

     return threecolumnlists; 
    } 

    public static async void readList(List<ThreeColumnList> tcl) 
    { 
     List<ThreeColumnList> a = tcl; 
     string _line; 
     var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Lists/splist.txt")); 
     using (var inputStream = await file.OpenReadAsync()) 
     using (var classicStream = inputStream.AsStreamForRead()) 
     using (var streamReader = new StreamReader(classicStream)) 
     { 
      while (streamReader.Peek() >= 0) 
      { 
       Debug.WriteLine("Line"); 
       _line = streamReader.ReadLine(); 
       //Debug.WriteLine(string.Format("the line is {0}", _line)); 
       string _first = "" + _line.Split('-')[0]; 
       string _second = "" + _line.Split('-')[1]; 
       string _third = "" + _line.Split('-')[2]; 

       a.Add(new ThreeColumnList { Name = _first, Age = _second, Job = _third }); 
      } 
     } 
    } 

    public static async void tryAgain(List<ThreeColumnList> tcl) 
    { 
     //Loading Folder 
     var _folder = Windows.ApplicationModel.Package.Current.InstalledLocation; 
     _folder = await _folder.GetFolderAsync("Lists"); 

     //Get the file 
     var _file = await _folder.GetFileAsync("splist.txt"); 

     // read content 
     IList<string> _ReadLines = await Windows.Storage.FileIO.ReadLinesAsync(_file); 

     int i = 0; 
     foreach (var _line in _ReadLines) 
     { 
      i++; 
      string _first = "" + _line.Split('-')[0]; 
      string _second = "" + _line.Split('-')[1]; 
      string _third = "" + _line.Split('-')[2]; 
      tcl.Add(new ThreeColumnList { Name = _first, Age = _second, Job = _third }); 
     } 
     Debug.WriteLine("Count is " + i); 
    } 
} 

在這種情況下與該文件被一分爲三,文本文件的樣本是這樣的

Bloggs, Joe-25-Engineer 
Flynn, John-43-Assistant 
Sherriff, Patsy-54-Manager 
!-!-! 

該行! - ! - !是一個分隔線,但它仍然會顯示! ! !在屏幕上分裂後 -

最初我試圖抓住文件的內容並將它們返回給GetList()並將內容處理到列表中,但我沒有運氣。

然後我決定嘗試將列表傳遞給抓取內容並在那裏填充List的方法。

我所做的兩個功能都是在屏幕上顯示內容,但並不一致。 ReadList()似乎更頻繁地使用tryAgain(),但它每次都不起作用。

此外,只是爲了說明,我已經嘗試過這種情況,我沒有拆分文件每一行的內容,而且我看到的問題只是有時會加載。

I was following this video to get the initial list working。一旦我得到這個工作,然後我開始從文件中讀取。

我有一種感覺,我真的很接近,但我不確定。

任何有關我要去哪裏的錯誤建議都是錯誤的?

謝謝!

+0

可以顯示(的一部分)輸入文件? – Sybren

+0

@sybren對不起,是的!我曾打算補充一點!我已經用示例更新了帖子。我也嘗試過這種方式,我沒有將文件中的每一行都分開,我只使用一列,並且只在有時候纔有效。該文本文件中的數據就像任何帶有新行的文本文件一樣。謝謝! – microbenny

+0

我調試你的代碼並且工作正常。我相信你的代碼部分很好。令我擔心的是xaml部分。你如何展示你的數據?你可以添加xaml部分以及如何傳遞元素中的數據? – Stamos

回答

1

嘗試實施了用於通知客戶INotifyPropertyChanged的和的ObservableCollection接口,通常是結合的客戶端,即屬性值已更改。

也使用任務來加載數據。

編輯:

MainPage.cs.xaml

using System; 
using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.ComponentModel; 
using System.Diagnostics; 
using System.IO; 
using System.Net.Http; 
using System.Net.Sockets; 
using System.Threading.Tasks; 
using Windows.Foundation.Collections; 
using Windows.Storage; 
using Windows.UI.Xaml; 
using Windows.UI.Xaml.Controls; 

namespace TestUWP 
{ 
    /// <summary> 
    /// An empty page that can be used on its own or navigated to within a Frame. 
    /// </summary> 
    public sealed partial class MainPage : Page 
    { 
     private ObservableCollection<ThreeColumnList> threeColumnLists; 

     public ObservableCollection<ThreeColumnList> ThreeColumnLists 
     { 
      get { return threeColumnLists ?? (threeColumnLists = new ObservableCollection<ThreeColumnList>()); } 
      set { threeColumnLists = value; } 
     } 
     public MainPage() 
     { 
      this.InitializeComponent(); 
      LoadData(); 

     } 

     private async void LoadData() 
     { 
      //you can also change the private threeColumnLists to a static 
      // and do 
      //if(ThreeColumnLists.Count==0) 
      // ThreeColumnLists = await ThreeColumnListManager.GetListAsync(); 
      ThreeColumnLists = await ThreeColumnListManager.GetListAsync(); 
      //can also do 
      // await ThreeColumnListManager.readList(ThreeColumnLists); 
     } 

    } 

    public class ThreeColumnList : INotifyPropertyChanged 
    { 
     private string name = string.Empty; 
     public string Name { get { return name; } set { name = value; NotifyPropertyChanged("Name"); } } 

     private string age = string.Empty; 
     public string Age { get { return age; } set { age = value; NotifyPropertyChanged("Age"); } } 

     private string job = string.Empty; 
     public string Job { get { return job; } set { job = value; NotifyPropertyChanged("Job"); } } 

     //PropertyChanged handers 
     public event PropertyChangedEventHandler PropertyChanged; 

     public void NotifyPropertyChanged(string propertyName) 
     { 
      if (PropertyChanged != null) 
      { 
       PropertyChanged(this, 
        new PropertyChangedEventArgs(propertyName)); 
      } 
     } 
    } 
    public class ThreeColumnListManager 
    { 
     public static async Task<ObservableCollection<ThreeColumnList>> GetListAsync() 
     { 
      var threecolumnlists = new ObservableCollection<ThreeColumnList>(); 

      //Add a dummy row to present something on screen 
      threecolumnlists.Add(new ThreeColumnList { Name = "Name1", Age = "Age1", Job = "Job1" }); 

      //First working method 
      await readList(threecolumnlists); 

      //Second Working Method 
      //tryAgain(threecolumnlists); 

      return threecolumnlists; 
     } 

     public static async Task readList(ObservableCollection<ThreeColumnList> tcl) 
     { 
      string _line; 
      var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Lists/slplist.txt")); 
      using (var inputStream = await file.OpenReadAsync()) 
      using (var classicStream = inputStream.AsStreamForRead()) 
      using (var streamReader = new StreamReader(classicStream)) 
      { 
       while (streamReader.Peek() >= 0) 
       { 
        Debug.WriteLine("Line"); 
        _line = streamReader.ReadLine(); 
        //Debug.WriteLine(string.Format("the line is {0}", _line)); 
        string _first = "" + _line.Split('-')[0]; 
        string _second = "" + _line.Split('-')[1]; 
        string _third = "" + _line.Split('-')[2]; 

        tcl.Add(new ThreeColumnList { Name = _first, Age = _second, Job = _third }); 
       } 
      } 
     } 

     public static async Task tryAgain(ObservableCollection<ThreeColumnList> tcl) 
     { 
      //Loading Folder 
      var _folder = Windows.ApplicationModel.Package.Current.InstalledLocation; 
      _folder = await _folder.GetFolderAsync("Lists"); 

      //Get the file 
      var _file = await _folder.GetFileAsync("splist.txt"); 

      // read content 
      IList<string> _ReadLines = await Windows.Storage.FileIO.ReadLinesAsync(_file); 

      int i = 0; 
      foreach (var _line in _ReadLines) 
      { 
       i++; 
       string _first = "" + _line.Split('-')[0]; 
       string _second = "" + _line.Split('-')[1]; 
       string _third = "" + _line.Split('-')[2]; 
       tcl.Add(new ThreeColumnList { Name = _first, Age = _second, Job = _third }); 
      } 
      Debug.WriteLine("Count is " + i); 
     } 
    } 
} 

MainPage.xaml中

<Page 
x:Class="TestUWP.MainPage" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:local="using:TestUWP" 
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
mc:Ignorable="d"> 

<Page.Resources> 
    <!-- x:DataType="<Name Of Class>" --> 
    <DataTemplate x:Key="ThreeColumnListDataTemplate" x:DataType="local:ThreeColumnList"> 
     <StackPanel Orientation="Horizontal" HorizontalAlignment="Left"> 
      <TextBlock Grid.Column="0" Text="{x:Bind Name}" HorizontalAlignment="Left" FontSize="16" Margin="20,20,20,20" /> 
      <TextBlock Grid.Column="1" Text="{x:Bind Age}" HorizontalAlignment="Left" FontSize="16" Margin="20,20,20,20" /> 
      <TextBlock Grid.Column="2" Text="{x:Bind Job}" HorizontalAlignment="Right" FontSize="16" Margin="20,20,20,20" /> 
     </StackPanel> 
    </DataTemplate> 
</Page.Resources> 

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> 

    <Grid.RowDefinitions> 
     <RowDefinition Height="*" /> 
     <RowDefinition Height="100" /> 
    </Grid.RowDefinitions> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="2*" /> 
     <ColumnDefinition Width="*" /> 
     <ColumnDefinition Width="*" /> 

    </Grid.ColumnDefinitions> 
    <TextBlock Grid.Row="1" 
       Name="ResultTextBlock" 
       FontSize="24" 
       Foreground="Red" 
       FontWeight="Bold" 
       Margin="20,20,0,0" /> 
    <!-- ItemsSource="x:Bind <Variable from the CS(Code) Class> --> 
    <ListView Grid.ColumnSpan="3" ItemsSource="{x:Bind ThreeColumnLists}" 
       ItemTemplate="{StaticResource ThreeColumnListDataTemplate}"> 
    </ListView> 

</Grid> 

輸出:

Output

+0

謝謝,但我有問題,如果你能幫助。最初我在'SPList.xaml.cs'文件中遇到了問題,但是我發現了一個在線解決方案,將公共ObservableCollection ThreeColumnLists'更改爲'private',從而解決了這個問題。然後我在XAML中遇到了一個問題,但是這是因爲我在之前的代碼中使用了不同的列表名稱,所以我將它更新爲指向'threeColumnLists'。在這個改變之後,我可以構建並運行,但是當我點擊進入頁面加載列表時,應用程序崩潰了。它顯示它在嘗試加載新頁面時找不到SPList。任何想法? – microbenny

+0

不要將公共ObservableCollection ThreeColumnLists改爲私有。確保'xmlns:data =「使用:TrackingAssistant.Model」'和' '指向正確的位置。 – Stamos

+0

我添加了我的完整解決方案與輸出檢查了這一點,找出你做錯了什麼。 – Stamos

-2

的肢體,走出這裏,但是:

的異步操作意味着它可以在不同的線程中運行,因此它可能是讀取文件(ThreeColumnList列表)最終的結果是生活在不同的線。您是否收到(或阻止)加載文件期間或之後發生的異常?您可能會考慮在綁定發生之前重新檢查您是否將列表編組到UI線程,如果它的所有者線程不是UI線程以避免此問題。

+1

轉移到閱讀中,我建議你閱讀更多有關'async \ await'的內容。 –

0

你必須awaitWait()Task。從
public static async void readList(List<ThreeColumnList> tcl)

更改簽名
public static async Task readList(List<ThreeColumnList> tcl)
並調用它像readList(threecolumnlists).Wait();

這打破你的代碼的不同步性,但會奏效。 最好的辦法是改變GetList()是異步和任務運行此展示給用戶微調或進度條:

public SPList() 
{ 
    this.InitializeComponent(); 
    Task.Run(async() => 
    { 
     IsLoading = true; 
     ThreeColumnLists = await ThreeColumnListManager.GetList(); 
     IsLoading = false; 
    } 
} 

private bool _isLoading; 
public bool IsLoading 
{ 
    get { return _isLoading; } 
    set 
    { 
     if(_isLoading != value) 
     { 
      _isLoading = value; 
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsLoading)); 
     } 
    } 
} 
+0

謝謝。 首先我試着用'.Wait()'方法。當我試圖在這個改變後運行應用程序時,一旦我點擊按鈕來加載文件,它就會掛起。 然後我按照你的建議更改了'GetList()',這樣工作起來更好。但它每次都不會加載。它將成功加載大約80%的時間,這是一個巨大的改進。 'PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(nameof(IsLoading));'在'PropertyChanged?'的代碼中顯示一個異常,所以現在我已經評論了這一點。時間?? 謝謝! – microbenny

+0

另外,我剛剛注意到,當數據沒有完全加載,它甚至沒有顯示虛擬行被編碼到屏幕上的列表中。所以它幾乎像現在似乎有一個問題與清單<>,但不是文本文件!... – microbenny

+0

對於'PropertyChanged'工作,你的類需要實現'INotifyPropertyChanged'接口。 –