Switching from ApplicationData.Current.LocalFolder to Knownfolders.DocumentsLibrary

310 views Asked by At

I'm currently developing an app for a visitor kiosk for a gravesite where one of the functions pulls data from a csv file and uses said data to populate a listview. The following code is what takes the data and returns them in a list type grave.

    public  class Grave 
    {
        public string plots { get; set; }
        public string DOBS { get; set; }
        public string lastNames { get; set; }
        public string firstNames { get; set; }
        public string companys { get; set; }
        public string regts { get; set; }
        public string unitTypes { get; set; }
        public string states { get; set; }
        public string ranks { get; set; }
        public string sections { get; set; }
        public string image { get; set; }
        public string text { get; set; }
        public string notenums { get; set; }
     }



public class GraveManager
{



    public  static  List<Grave> GetGrave() 
    {   //points to desired folder
        StorageFolder folder = ApplicationData.Current.LocalFolder;

        string csvPath = folder.Path + @"\PGexcel.csv";
        //loads .csv file from folder
        Csv csv = new Csv();

        //property that tells csv parser to not treat the first row as data
        csv.HasColumnNames = true;

        bool success1;
        success1 = csv.LoadFile(csvPath);

        //name of columns
        string plot = "Plot", DOB = "Date_of_Death", lastName = "Last_Name", firstName = "First_Name", company = "Company", regt = "Regt", state = "State", unitType = "Unit_Type", Rank = "Rank", Section = "Section", Notables= "Notables";


        //initialize string of arrays for each column
        string[] OCplots = new string[csv.NumRows];
        string[] OCDOBS = new string[csv.NumRows];
        string[] OClastNames = new string[csv.NumRows];
        string[] OCfirstNames = new string[csv.NumRows];
        string[] OCcompanys = new string[csv.NumRows];
        string[] OCregts = new string[csv.NumRows];
        string[] OCunitTypes = new string[csv.NumRows];
        string[] OCstates = new string[csv.NumRows];
        string[] OCranks = new string[csv.NumRows];
        string[] OCsections = new string[csv.NumRows];
        string[] OCimage = new string[csv.NumRows];
        string[] OCtext = new string[csv.NumRows];
        string[] OCnotenums = new string[csv.NumRows];


        //populates the arrays with values from .csv file
        for (int i = 0; i < csv.NumRows; i++)
        {

            OCplots[i] = csv.GetCellByName(i, plot);
            OCDOBS[i] = csv.GetCellByName(i, DOB);
            OClastNames[i] = csv.GetCellByName(i, lastName);
            OCfirstNames[i] = csv.GetCellByName(i, firstName);
            OCcompanys[i] = csv.GetCellByName(i, company);
            OCregts[i] = csv.GetCellByName(i, regt);
            OCunitTypes[i] = csv.GetCellByName(i, unitType);
            OCranks[i] = csv.GetCellByName(i, Rank);
            OCsections[i] = csv.GetCellByName(i, Section);
            OCstates[i] = csv.GetCellByName(i, state);
            OCnotenums[i] = csv.GetCellByName(i, Notables); 
        }



        //concantenate arrays with .jpg .txt to call for corresponding files
        for (int i = 0; i < csv.NumRows; i++)
        {
            //OCimage[i] = "C:/Users/POGR_ADMIN/AppData/Local/Packages/6b3614f6-6a5f-48fc-9687-80291e70b64d_phwtyg9y34v1t/LocalState/" + OCplots[i] + ".jpg";
            OCimage[i] = folder.Path + @"\" + OCplots[i] + ".jpg";
            OCtext[i] = folder.Path + @"\"+ OCplots[i] + ".txt";  
        }

        var graves = new List<Grave>();



        //attempt to populate List using the for loop
        for (int i = 0; i < csv.NumRows; i++)
        {
            graves.Add(new Grave { plots= OCplots[i], DOBS = OCDOBS[i], lastNames = OClastNames[i], firstNames = OCfirstNames[i], companys = OCcompanys[i], regts = OCregts[i], states = OCstates[i], unitTypes = OCunitTypes[i],ranks = OCranks[i], sections = OCsections[i], image = OCimage[i], text = OCtext[i], notenums = OCnotenums[i] });

        }




        return graves;             

    }
}

I then initialize a list type grave on another page and fill it by calling the method when the constructor is called. Which is shown here:

   public List<Grave> Graves;

   public FindaGrave()
    {
        this.InitializeComponent();
        GraveInitializer();

    }

     public void GraveInitializer()
    {
        Graves = GraveManager.GetGrave();
    }

This code works perfectly and fine and populates the listview exactly how I envisioned. However, it has been brought to my attention that there are many errors in the csv file that they have found and plan on finding due to human error. With that being said, they want to be able to make a change the csv file and the changes will show up after they reload the app(without any help from me). Due to the local state folder being packaged the only way I saw fit to do so would be to change StorageFolder folder = ApplicationData.Current.LocalFolder; into StorageFolder folder = KnownFolders.DocumentsLibrary;

I felt that if I made sure the file was in the Document Library, added the capability in the app package manifest like so <uap:Capability Name="documentsLibrary" /> and add the appropriate filetype association that it should work the same. However, when i run it, the list no longer shows up, and after I debugged a little bit there is no longer a value for folder.Path and the string csvPath just becomes equal to `"\PGexcel.csv" . I am at a complete loss because what i thought was gonna be a quick fix ended up being something very difficult, furthermore I'm new to UWP so that doesn't help. I've looked for days and can not find the solution and any assistance on this matter will be greatly appreciated. You would be a life saver!!

2

There are 2 answers

2
Dave Smits On

oke i checked your code and problem is that UWP apps are kind of sandboxed and only have full access to the ApplicationData. Even if you manage to get a full path outside your application data you are not able to just open it. You need to open them via the KnownFolders class or save them in StorageApplicationPermissions class

Best way would use the Storiage Api's to open the filestream and pass that to your csv parser, but i am not sure if your csv parsers accepts a stream

3
Martin Zikmund On

Because UWP apps need to be safe, they are not allowed to access non-application data file system locations directly by using paths.

You can still use StorageFile APIs though, and it should be sufficient in your case if your CSV library supports input from string, instead of file.

public static async Task<List<Grave>> GetGraveAsync() 
{   
    //points to desired folder
    StorageFolder folder = ApplicationData.Current.LocalFolder;
    //find the file
    StorageFile csvFile = await folder.GetFileAsync( "PGexcel.csv" );


    //loads .csv file from folder
    Csv csv = new Csv();

    //property that tells csv parser to not treat the first row as data
    csv.HasColumnNames = true;

    bool success1;

    //load the CSV data from string
    success1 = csv.LoadFromString( await FileIO.ReadAllText(csvFile) );

    //... rest of your code

    return graves;             
}

StorageApplicationPermissions.FutureAccessList

The simplest solution to your issue would be to let the users choose the file on the first launch of the app using the FileOpenPicker and then store it using the StorageApplicationPermissions.FutureAccessList API. This API allows you to save the access permission to 1000 storage items, so that you can access the file the user selected. even over multiple launches of the app.