0

I am trying to move xml configure files from the installation directory to the local directory. When it gets to StorageFolder.GetFilesAsync() it freezes the app and never recovers.

The code I am calling is inside a Windows RT project so I can't make it async at the public method. Seems to make no difference if I make the client UWP app method an async call.

private async void InstallButton_Click(object sender, RoutedEventArgs e)
{
    await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
    {
        bool installed = FileManager.Install(StorageLocation.Local);
    });

}

public static bool Install(StorageLocation location)
{
    return InstallAsync(location).Result;
}  

private static async Task<bool> InstallAsync(StorageLocation location)
{
    try
    {
        StorageFolder destinationFolder = null;
        if (location == StorageLocation.Local)
        {
            destinationFolder = ApplicationData.Current.LocalFolder;
        }
        else if (location == StorageLocation.Roaming)
        {
            destinationFolder = ApplicationData.Current.RoamingFolder;
        }

        if (destinationFolder == null)
        {
            return false;
        }

        StorageFolder folder = Package.Current.InstalledLocation;
        if (folder == null)
        {
            return false;
        }

        // Language files are installed in a sub directory
        StorageFolder subfolder = await folder.GetFolderAsync(languageDirectory);
        if (subfolder == null)
        {
            return false;
        }

        // Get a list of files

        IReadOnlyList<StorageFile> files = await subfolder.GetFilesAsync();

        foreach (StorageFile file in files)
        {
            if (file.Name.EndsWith(".xml"))
            {
                await file.CopyAsync(destinationFolder);
            }
        }
    }
    catch (Exception)
    { }

    return IsInstalled(location);
}
Haydn
  • 293
  • 1
  • 2
  • 13
  • 1
    Try to call `await FileManager.InstallAsync(StorageLocation.Local);` in your button click instead of waiting for it. Don't make async code run synchronously - you may alse read about deadlocks at [Stephen Cleary's blog](https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html). Another thing - what is `IsInstalled(location)`? - is it another method which synchronously waits for async code (like `.Result`)? – Romasz Apr 24 '17 at 05:02
  • Another question - why you run this on *Distpatcher*? – Romasz Apr 24 '17 at 05:08

1 Answers1

1

To quickly fix your problem, make that method public async and pass it down the task to the RunAsync call.

private async void InstallButton_Click(object sender, RoutedEventArgs e)
{
    await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
    {
        bool installed = await FileManager.InstallAsync(StorageLocation.Local);
    });
}

Also, does FileManager modify the UI? If not, you can just await it directly without the dispatcher.

private async void InstallButton_Click(object sender, RoutedEventArgs e)
{
    bool installed = await FileManager.InstallAsync(StorageLocation.Local);
}
Laith
  • 6,071
  • 1
  • 33
  • 60
  • I would think one could await the `InstallAsync()` method, regardless of whether it modifies the UI (it should not, but it also shouldn't matter). Why does your proposal above suggest using `RunAsync()`? Are you under the misimpression that the UI thread is blocked when a method is at an `await` statement? – Peter Duniho Apr 24 '17 at 05:24
  • Thanks for the quick reply. I don't have to update the UI. The problem with this is the FileManager is in a WinRT project. It cannot return a Task. That is why I created the Install wrapper methods to try an solve that. I guess that doesnt work. Maybe I could change them to one of the Windows Runtime types suggested in the exception message. – Haydn Apr 24 '17 at 05:30
  • You have marked it as a duplicate when the question you pointed to is nothing like the question I asked. – Haydn Apr 24 '17 at 05:47