greedyLump
greedyLump

Reputation: 250

UWP FolderPicker window opens but is frozen

The basic idea is I have a UWP app pulling user data from a json file saved locally, and at various times it may pull that full list of objects from the file, but it always checks that the user has set the location for the data, and if not, prompts via a FolderPicker for the user to set the location. In this case, I have combobox that helps filter the objects after selecting a criteria and entering text. Here's the call stack:

UWPMiniatures.exe!UWPMiniatures.Data.MiniDAL.SetSaveFolder() Line 98 C# Symbols loaded. UWPMiniatures.exe!UWPMiniatures.Data.MiniDAL.LoadAllAsync() Line 71 C# Symbols loaded. UWPMiniatures.exe!UWPMiniatures.Data.MiniDataService.Load() Line 36 C# Symbols loaded. UWPMiniatures.exe!UWPMiniatures.MainPage.FilterGridView(string submission) Line 156 C# Symbols loaded. UWPMiniatures.exe!UWPMiniatures.MainPage.SearchIcon_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e) Line 95 C# Symbols loaded.

So, working backwords, the FolderPicker is being called here:

private async Task SetSaveFolder()
{
    if(!StorageApplicationPermissions.FutureAccessList.ContainsItem("PickedFolderToken"))
    {
        FolderPicker folderPicker = new FolderPicker();
        folderPicker.SuggestedStartLocation = PickerLocationId.Desktop;
        folderPicker.FileTypeFilter.Add("*");
        folderPicker.CommitButtonText = "Pick A Folder To Save Your Data";
        StorageFolder folder = await folderPicker.PickSingleFolderAsync();
        if (folder != null)
        {
            // Application now has read/write access to all contents in the picked folder (including other sub-folder contents)
            StorageApplicationPermissions.FutureAccessList.AddOrReplace("PickedFolderToken", folder);
            var userFolder = await StorageApplicationPermissions.FutureAccessList.GetFolderAsync("PickedFolderToken");
            var file = await userFolder.CreateFileAsync("AllMinisList.json",CreationCollisionOption.OpenIfExists);
            var imagefolder = await userFolder.CreateFolderAsync("Images");
        }

    }
}

The folder picker dialog opens, with a blinking cursor next to Folder:, but nothing happens when I click anywhere, nor can i type in Folder: textbox. Now, putting this identical code in a new project and calling it in response to a click event works fine: Dialog opens, I make a new folder or pick an existing one, it gets added to future access list. Not sure how to else to troubleshoot this but the problem seems to lie out side the actual code calling the FolderPicker. here is the code for the other calling function

private void SearchIcon_Click(object sender, RoutedEventArgs e)
{
    FilterGridView(SearchTextBox.Text);
    SearchTextBox.Text = "";
}

    private async void FilterGridView(string submission)
{
    var selected = FilterComboBox.SelectedValue;

    miniDS = new MiniDataService();  

   if(selected.ToString()=="All")
    {
        MiniList.Clear();
        List<Miniature> fullList = await miniDS.Load();
        fullList.ForEach(m => MiniList.Add(m));
    }
    else if (selected.ToString() == "Quantity")
    {
        List<Miniature> fullList = await miniDS.Load();
        var templist = fullList.AsQueryable()
         .Where($"{selected} = @0", submission); ;
        MiniList.Clear();
        templist.ToList<Miniature>()
            .ForEach(m => MiniList.Add(m));
    }
    else
    {
        List<Miniature> fullList = await miniDS.Load();
        var templist = fullList.AsQueryable()
        .Where($"{selected}.StartsWith(@0)", submission);
        MiniList.Clear();
        templist.ToList<Miniature>()
            .ForEach(m => MiniList.Add(m));
    }
}

MiniDataService and MiniDal don't do much here other than pass the call along. Any ideas where I can look to troubleshoot this? UPDATE: Some additional info, I copied the code from SetSaveFolder() directly into a new event handler for a button, clicked it, I get FolderPicker, functions perfectly. But thats not at all the functionality needed. I need it to be called, directly or indirectly from my Data Service. So here's where its created:

 public sealed partial class MainPage : Page
    {
        /// <summary>
        /// MiniList is the list of minis currently being displayed
        /// </summary>
        private ObservableCollection<Miniature> MiniList;
        private MiniDataService miniDS;       
        private List<string> FilterComboList;
        private Miniature NewMini;

        public MainPage()
        {
            this.InitializeComponent();           
            miniDS = new MiniDataService();
            MiniList = new ObservableCollection<Miniature>();         
            FilterComboList = PopulateFilterCombo();
            NewMini = new Miniature();
            MyFrame.Navigate(typeof(MiniListPage), MiniList);
        }
...

So the problem seems to have something to do with the fact that FolderPicker is being called from this "static" object. Is this a thread issue? I thought in UWP I am always on the UI threadm and since at the top level an event handler is calling folderPicker I can't understand why the UI seems locked.

Upvotes: 1

Views: 276

Answers (1)

greedyLump
greedyLump

Reputation: 250

So i think I figured it out, though I have no idea why this happened. If anyone can clue me in, id appreciate it. So from the call List<Miniature> fullList = await miniDS.Load(); Here's that method:

 public async Task<List<Miniature>> Load()
        {
            return await minidal.LoadAllAsync();
        }

public async Task<List<Miniature>> LoadAllAsync()
        {

            List<Miniature> MiniCollection = new List<Miniature>();
            if (StorageApplicationPermissions.FutureAccessList.ContainsItem("PickedFolderToken"))
            {
                try
                {
                    var userFolder = await StorageApplicationPermissions.FutureAccessList.GetFolderAsync("PickedFolderToken");
                    var file = await userFolder.GetFileAsync("AllMinisList.json");
                    var data = await file.OpenReadAsync();

                    using (StreamReader stream = new StreamReader(data.AsStream()))
                    {
                        string text = stream.ReadToEnd();
                        MiniCollection = JsonConvert.DeserializeObject<List<Miniature>>(text);
                    }
                }
                catch(Exception e)
                {
                    throw e;
                }
            }
            else
            {
                SetSaveFolder().Wait();
                return MiniCollection;
            }

            return MiniCollection;
        }

So the problem was right here:

SetSaveFolder().Wait();

When I replace that with

await SetSaveFolder();

it works fine. I can click in the folderPicker, and it does what it's supposed to. I guess I though .Wait() was used when you aren't return anything other than but it seems there is more too it than that!

Upvotes: 1

Related Questions