UWP 10 C#。将文本文件读入一个List <>

问题描述:

让我开始说我是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

尝试实施了用于通知客户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

的肢体,走出这里,但是:

的异步操作意味着它可以在不同的线程中运行,因此它可能是读取文件(ThreeColumnList列表)最终的结果是生活在不同的线。您是否收到(或阻止)加载文件期间或之后发生的异常?您可能会考虑在绑定发生之前重新检查您是否将列表编组到UI线程,如果它的所有者线程不是UI线程以避免此问题。

+1

转移到阅读中,我建议你阅读更多有关'async \ await'的内容。 –

你必须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'接口。 –