UWP 10 C#. Reading a text file into a List<>

荒凉一梦 提交于 2019-12-22 14:46:27

问题


Let me start by saying that I'm brand new to UWP and the closest I have come to this language would be C++ about 12 years ago!

I'm writing an app for Windows Universal and in it I'll be reading different text files in line by line, split the contents of each line (Some files I won't need to split the line), add the data into a list and then show it on screen. I've tried many ways to do this but I haven't got it working correctly. I currently have two methods that are working, but not consistently. It will show the data but only sometimes. When I run the app (either in emulator or on local device) it may or may not show the data and then if I click to a different page and back into the list page, it may or may not show it again..

Here's the code.. In this case I'm splitting the contents of the text file into 3 strings splitting on a '-'

in my XAML.cs file

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

in my 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>

in ThreeColumnList.cs

class ThreeColumnList
{
    public string Name { get; set; }
    public string Age { get; set; }
    public string Job { get; set; }
}

In my 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);
    }
}

And in this case with the file being split into three, a sample of the text file would look like this

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

The line !-!-! is a seperator line but it will still display ! ! ! on screen after splitting on the -

Initially I was trying to grab the contents of the file and return them to GetList() and process the contents into the List there but I was having no luck.

Then I decided to try pass the list to the method that grabs the content and populate the List there.

Both the functions I have do display content to the screen but not consistently. ReadList() seems to work more frequently that tryAgain() but it still does not work every time.

Also, just to note, I've tried this where I'm not splitting the contents of each line of the file and I'm seeing the same issue where it will load only sometimes.

I was following this video to get the initial list working. Once I got this working then I moved onto reading in from file.

I have a feeling that I'm really close but I'm not sure.

Anyone any advice on where I'm going wrong?

Thanks!


回答1:


Try implementing INotifyPropertyChanged and ObservableCollection interfaces that are used to notify clients, typically binding clients, that a property value has changed.

Also use Task to load the data.

Edit:

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:




回答2:


You have to await or Wait() on Task.

Change signature from
public static async void readList(List<ThreeColumnList> tcl)
to
public static async Task readList(List<ThreeColumnList> tcl)
And invoke it like readList(threecolumnlists).Wait();

This breaks asynchrony of your code, but will work. The best way would be to change GetList() to be async and run this in Task showing spinner or progress bar to user:

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



回答3:


Going out on a limb here but:

The async operation means it can be run on a different thread so it's possible that the end result of reading the file (a list of ThreeColumnList) is living on a different thread. Do you receive (or have you suppressed) exceptions that occur during or shortly after loading a file? You might consider double-checking that you are marshalling the list to the UI thread before binding occurs if it's owner thread is not the UI thread to avoid this issue.



来源:https://stackoverflow.com/questions/36777515/uwp-10-c-reading-a-text-file-into-a-list

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!