Search code examples
c#.netmauimaui-windows

.Net MAUI IFilePicker error, Value does not fall within the expected range, if built with msbuilder


I'm building an app for windows only, that needs to consume a docx file using .net MAUI.

I use the suggested class IFilePicker, implemented it, and worked fine while debugging (both in debug and release mode).

So, after finished a preview version, I want to deploy unpacked, "like a portable version", using:

MSBuild.exe D:\Workspace\dotNet\WordReplacer\WordReplacer.App\ /restore /t:Publish /p:TargetFramework=net6.0-windows10.0.19041 /p:configuration=release /p:WindowsAppSDKSelfContained=true /p:Platform=x64 /p:PublishSingleFile=true /p:WindowsPackageType=None /p:RuntimeIdentifier=win10-x64

Everthing works fine just as debug, except for the FilePicker that doesn't work and gives me the error:

Value does not fall within the expected range

This error doesn't happen if I install a published package with a certificate. So maybe I'm missing something in the msbuilder workaround to generate an unpacked app.

I'm using the communitytoolkit.MVVM and the method that I use to pick the file stays in my viewmodel:

        private string _inputFilePath;
        
        [ObservableProperty]
        private string _inputFileNameText = "Select a input file";
        
        [RelayCommand]
        public async Task PickInputDocAsync()
        {
            try
            {
                var customFileType = new FilePickerFileType(
                    new Dictionary<DevicePlatform, IEnumerable<string>>
                    {
                        { DevicePlatform.WinUI, new[] { ".doc", ".docx" } },
                    });

                PickOptions options = new()
                {
                    PickerTitle = "Please select a document",
                    FileTypes = customFileType,
                };

                var result = await FilePicker.Default.PickAsync(options).ConfigureAwait(false);

                if (result != null)
                {
                    _inputFilePath = result.FullPath;
                    InputFileNameText = result.FileName;
                }

            }
            catch (Exception ex)
            {
                ErrorMessage = $"{ex.InnerException?.Message} Error: {ex.Message}, InputFilePath: {_inputFilePath}, InputFileName: {InputFileNameText}";
            }

Any clue how to fix it?


Solution

  • I've been trying to fix this error, but since I don't know much about msbuild itself, I take another approach.

    So, I finally got it working when I implemented a FilePicker specifically for the Windows platform.

    I take most of the code from this answer Folder Picker .NET MAUI, but, instead of folderpicker I use the filepicker. Check it out to know more about the implementation and the set up.

    How I do it:

    Create a Folder helper in the root folder app and create an interface ICustomPicker and a data transfer object(DTO).

    public interface ICustomPicker
    {
        Task<FileDto> PickFileAsync();
    }
    
    public class FileDto
    {
        public string DisplayName { get; set; }
        public string Name { get; set; }
        public string FullPath { get; set; }
    }
    

    Inside the Plataforms/Windows folder I created CustomFilePicker.cs

    public class CustomPicker : ICustomPicker
    {
        
         public async Task<FileDto> PickFileAsync()
            {
                try
                {
                    var picker = new WindowsFilePicker();
    
                    picker.FileTypeFilter.Add(".docx");
                    picker.FileTypeFilter.Add(".doc");
    
                    // Get the current window's HWND by passing in the Window object
                    var windowHandle = ((MauiWinUIWindow)App.Current.Windows[0].Handler.PlatformView).WindowHandle;
    
                    // Associate the HWND - window handler, with the file picker
                    WinRT.Interop.InitializeWithWindow.Initialize(picker, windowHandle);
    
                    var storageFile = await picker.PickSingleFileAsync();
    
                    if (storageFile != null)
                    {
                        return new FileDto()
                        {
                            DisplayName = storageFile.DisplayName,
                            Name = storageFile.Name,
                            FullPath = storageFile.Path
                        };
                    }
                }
                catch
                {
                    // Ignored
                }
                return null;
    
            }
    }
    

    Register the DI in my MauiProgram.cs

    #if WINDOWS
                builder.Services.AddTransient<ICustomPicker, Platforms.Windows.CustomPicker>();
    #endif
    

    then in my view model I simply call it

    
    private readonly ICustomPicker _customPicker;
    public MainViewModel(ICustomPicker customPicker,)
    {        
        _customPicker = customPicker;         
    }
    
    [RelayCommand]
    public async Task PickInputDocAsync(){
    
        var file = await _customPicker.PickFileAsync().ConfigureAwait(false);
    
        if (file != null)
        {
            //do something
        }
    }
    

    Probably this problem will disappear (I hope) when MAUI releases a proper unpacked publish option.

    Note: Right now, I just test this approach in Windows 11.