locked
System.Exception "Element not found" when calling FileOpenPicker.PickSingleFileAsync RRS feed

  • Question

  • Hello,

    I have a button with a command like this:

    <AppBarButton IsCompact="True" Icon="Add" Command="{Binding AddSmallTileImageCommand}" Style="{StaticResource SmallAppBarButtonStyle}" />

    And that command had the following code:

    public RelayCommand AddSmallTileImageCommand { get { if (_addSmallTileImageCommand == null) { _addSmallTileImageCommand = new RelayCommand( async () => { // Create FileOpenPicker instance. FileOpenPicker openPicker = new FileOpenPicker(); openPicker.SettingsIdentifier = "Images"; openPicker.ViewMode = PickerViewMode.Thumbnail; openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary; openPicker.FileTypeFilter.Add(".jpg"); openPicker.FileTypeFilter.Add(".jpeg"); openPicker.FileTypeFilter.Add(".png");

    StorageFile file = await openPicker.PickSingleFileAsync(); if (file != null) { Uri newImageUri = await ImageHelper.SaveImageToTempFolderAsync(file, "SmallLogo"); await _tile.AddSmallLogoImageAsync(newImageUri); } }, () => !_smallTileImageAvailable); } return _addSmallTileImageCommand; } } private RelayCommand _addSmallTileImageCommand;

    I got some reports of users having this issue sporadically and the only way I was able to reproduce it was forcing the command to execute the code in a non-UI thread using Task.Run, so I modified the code to make sure it would always execute in the UI thread:

    public RelayCommand AddSmallTileImageCommand
            {
                get
                {
                    if (_addSmallTileImageCommand == null)
                    {
                        _addSmallTileImageCommand = new RelayCommand(
                            async () =>
                            {
                                // Create FileOpenPicker instance.
                                FileOpenPicker openPicker = new FileOpenPicker();
                                openPicker.SettingsIdentifier = "Images";
                                openPicker.ViewMode = PickerViewMode.Thumbnail;
                                openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
                                openPicker.FileTypeFilter.Add(".jpg");
                                openPicker.FileTypeFilter.Add(".jpeg");
                                openPicker.FileTypeFilter.Add(".png");
    
                                // If we're running in the UI thread.
                                if (CoreApplication.MainView.CoreWindow.Dispatcher.HasThreadAccess)
                                {
                                    StorageFile file = await openPicker.PickSingleFileAsync();
                                    if (file != null)
                                    {
                                        Uri newImageUri = await ImageHelper.SaveImageToTempFolderAsync(file, "SmallLogo");
                                        await _tile.AddSmallLogoImageAsync(newImageUri);
                                    }
                                }
                                else
                                {
                                    // Use Dispatcher to avoid System.Exception "Element not found".
                                    // http://sertacozercan.com/2013/10/fixing-element-not-found-exception-from-hresult-0x80070490-error-in-windows-8-x/
                                    EventWaitHandle waitHandle = new ManualResetEvent(false);
                                    await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
                                    {
                                        StorageFile file = await openPicker.PickSingleFileAsync();
                                        if (file != null)
                                        {
                                            Uri newImageUri = await ImageHelper.SaveImageToTempFolderAsync(file, "SmallLogo");
                                            await _tile.AddSmallLogoImageAsync(newImageUri);
                                        }
    
                                        waitHandle.Set();
                                    });
    
                                    // Wait for the UI thread to finish, even though the RunAsync call is awaited execution continues.
                                    // http://stackoverflow.com/questions/11427999/how-to-pass-value-from-dispatcher-or-task-to-outside
                                    waitHandle.WaitOne();
                                }
                            },
                            () => !_smallTileImageAvailable);
                    }
    
                    return _addSmallTileImageCommand;
                }
            }
            private RelayCommand _addSmallTileImageCommand;
    After releasing an update with the new code I just got a report of this issue happening again so now I'm lost, is there a situation where Dispatcher.HasThreadAccess can be true when the command is executed in a non-UI thread? Or is there something else that could make FileOpenPicker.PickSingleFileAsync throw that exception?
    Thursday, November 28, 2013 12:12 PM

Answers

  • Thanks for the clarification Gabriel.

    I think you are chasing the wrong problem.  How in the past (before your change) could you possibly be on the wrong thread randomly?  I think you saw a similar exception (that happens all the time) and tried to apply it to your situation.

    I would recommend putting Try catch handlers in your code and get the inner exception (if available) and line that the problem occurs.  Also get feedback from the customer to see how often and when the error occurs (maybe the main windows is not activated or something?).


    Jeff Sanders (MSFT)

    @jsandersrocks - Windows Store Developer Solutions @WSDevSol
    Getting Started With Windows Azure Mobile Services development? Click here
    Getting Started With Windows Phone or Store app development? Click here
    My Team Blog: Windows Store & Phone Developer Solutions
    My Blog: Http Client Protocol Issues (and other fun stuff I support)

    Monday, December 2, 2013 4:23 PM
    Moderator
  • I had the same problem. I think the issue is when the user double clicks on the open button. I think you can only show 1 file picker at a time. So if you get a double click, the app might try to show 2 of them and that will cause an exception. A simple flag that is set when you open a file picker should do it.
    Monday, February 3, 2014 10:09 PM

All replies

  • What line are you getting this exception on?  You said on the PickSingleFileAsync and the solution you quote is for the creation of the picker object.  I don't see anywhere you are logging the exception line in your code.  What is the ImageHelper class you are referencing?  Why do you pass a file picked from the Pictures location and then 'Save to Temp Folder' as the call suggests?

    Jeff Sanders (MSFT)

    @jsandersrocks - Windows Store Developer Solutions @WSDevSol
    Getting Started With Windows Azure Mobile Services development? Click here
    Getting Started With Windows Phone or Store app development? Click here
    My Team Blog: Windows Store & Phone Developer Solutions
    My Blog: Http Client Protocol Issues (and other fun stuff I support)

    Monday, December 2, 2013 2:40 PM
    Moderator
  • Hello Jeff, thanks for your help.

    The exception is thrown in the PickSingleFileAsync call, I should have cleaned the code instead of just copy and paste it, sorry. Here's a simple sample I just wrote where the exception is thrown:

    <Page
        x:Class="ElementNotFoundSample.MainPage"
        DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:ElementNotFoundSample"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    
        <StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
            <Button Content="Pick file (throws exception)" Command="{Binding FilePickerCommand}" />
            <Button Content="Pick file (with fix)" Command="{Binding FilePickerFixCommand}" />
        </StackPanel>
    </Page>
    using System;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Windows.Input;
    using Windows.ApplicationModel.Core;
    using Windows.Storage;
    using Windows.Storage.Pickers;
    using Windows.UI.Core;
    using Windows.UI.Xaml.Controls;
    
    namespace ElementNotFoundSample
    {
        public class MainPageViewModel
        {
            public RelayCommand FilePickerCommand
            {
                get
                {
                    if (_filePickerCommand == null)
                    {
                        _filePickerCommand = new RelayCommand(async () =>
                        {
                            await Task.Run(async () =>
                            {
                                FileOpenPicker openPicker = new FileOpenPicker();
                                openPicker.FileTypeFilter.Add("*");
    
                                StorageFile file = await openPicker.PickSingleFileAsync();
                                if (file != null)
                                {
                                    // Do something
                                }
                            });
                        });
                    } return _filePickerCommand;
                }
            }
            private RelayCommand _filePickerCommand;
    
            public RelayCommand FilePickerFixCommand
            {
                get
                {
                    if (_filePickerFixCommand == null)
                    {
                        _filePickerFixCommand = new RelayCommand(async () =>
                        {
                            await Task.Run(async () =>
                            {
                                FileOpenPicker openPicker = new FileOpenPicker();
                                openPicker.FileTypeFilter.Add("*");
    
                                if (CoreApplication.MainView.CoreWindow.Dispatcher.HasThreadAccess)
                                {
                                    StorageFile file = await openPicker.PickSingleFileAsync();
                                    if (file != null)
                                    {
                                        // Do something
                                    }
                                }
                                else
                                {
                                    EventWaitHandle waitHandle = new ManualResetEvent(false);
                                    await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
                                    {
                                        StorageFile file = await openPicker.PickSingleFileAsync();
                                        if (file != null)
                                        {
                                            // Do something
                                        }
    
                                        waitHandle.Set();
                                    });
    
                                    waitHandle.WaitOne();
                                }
                            });
                        });
                    } return _filePickerFixCommand;
                }
            }
            private RelayCommand _filePickerFixCommand;
        }
    
        public sealed partial class MainPage : Page
        {
            public MainPageViewModel DefaultViewModel
            {
                get { return this.defaultViewModel; }
            }
            private MainPageViewModel defaultViewModel = new MainPageViewModel();
    
            public MainPage()
            {
                this.InitializeComponent();
            }
        }
    
        public class RelayCommand : ICommand
        {
            private readonly Action _execute;
            private readonly Func<bool> _canExecute;
            public event EventHandler CanExecuteChanged;
    
            public RelayCommand(Action execute)
                : this(execute, null)
            {
            }
    
            public RelayCommand(Action execute, Func<bool> canExecute)
            {
                if (execute == null)
                    throw new ArgumentNullException("execute");
                _execute = execute;
                _canExecute = canExecute;
            }
    
            public bool CanExecute(object parameter)
            {
                return _canExecute == null ? true : _canExecute();
            }
    
            public void Execute(object parameter)
            {
                if (CanExecute(parameter))
                {
                    _execute();
                }
            }
    
            public void RaiseCanExecuteChanged()
            {
                var handler = CanExecuteChanged;
                if (handler != null)
                {
                    handler(this, EventArgs.Empty);
                }
            }
        }
    }

    So, if you click the first button the exception is thrown since PickSingleFileAsync is called from a non-UI thread and if you click the second button it works correctly since Dispatcher.HasThreadAccess is false and PickSingleFileAsync is called using the Dispatcher.

    The issue is that somehow the app has thrown that exception in that method for a user using the code from the second button, and I have no clue how that could happen with that check and the use of the Dispatcher.

    I have no way of knowing the exact line that threw the exception for that user since, as you say, it's not being logged, all I have is a stack trace:

    System.Exception   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
       at PinMore.ViewModels.TileSetupViewModel.<<get_AddSmallTileImageCommand>b__a9>d__b8.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<ThrowAsync>b__4(Object state)
       at System.Threading.WinRTSynchronizationContext.Invoker.InvokeCore()

    What the ImageHelper method does is copy the file to ApplicationData.Current.TemporaryFolder using the StorageFile.CopyAsync method and return its Uri. I do that because the images the user adds are shown in a Canvas and I set its Background property to an ImageBrush that has that Uri as ImageSource.


    Monday, December 2, 2013 3:47 PM
  • Thanks for the clarification Gabriel.

    I think you are chasing the wrong problem.  How in the past (before your change) could you possibly be on the wrong thread randomly?  I think you saw a similar exception (that happens all the time) and tried to apply it to your situation.

    I would recommend putting Try catch handlers in your code and get the inner exception (if available) and line that the problem occurs.  Also get feedback from the customer to see how often and when the error occurs (maybe the main windows is not activated or something?).


    Jeff Sanders (MSFT)

    @jsandersrocks - Windows Store Developer Solutions @WSDevSol
    Getting Started With Windows Azure Mobile Services development? Click here
    Getting Started With Windows Phone or Store app development? Click here
    My Team Blog: Windows Store & Phone Developer Solutions
    My Blog: Http Client Protocol Issues (and other fun stuff I support)

    Monday, December 2, 2013 4:23 PM
    Moderator
  • So are button commands guaranteed to execute on the UI thread?

    I assumed it would happen in the call to PickSingleFileAsync since forcing it to run on a non-UI thread results in the exact same stack trace and error message (Element not found. (Exception from HRESULT: 0x80070490)), which I somehow didn't include in the previous reply. I also thought so since it is the only method call in there to external code, shouldn't the stack trace point to the SaveImageToTempFolder method if the exception was thrown there?

    I will add try catch handlers in the next update and wait for someone to have this issue again, hopefully the exception will be more helpful then, at least I'll know for sure which line throws it. So far it has happened only to 3 users, all of them clicked/tapped that button right before it crashed and it has only happened once for each of them so it seems to happen randomly and very infrequently.

    Tuesday, December 3, 2013 11:03 AM
  • I had the same problem. I think the issue is when the user double clicks on the open button. I think you can only show 1 file picker at a time. So if you get a double click, the app might try to show 2 of them and that will cause an exception. A simple flag that is set when you open a file picker should do it.
    Monday, February 3, 2014 10:09 PM
  • Thank you for taking the time to answer.

    Calling a file picker when it's already opened does throw an exception, unfortunately it's a System.UnauthorizedAccessException. I didn't include the flag in the code I posted but it's there in the actual code because I found that issue too. I'll mark it as answer though since it could help someone else having issues with the file picker.

    Tuesday, February 4, 2014 9:58 AM