Search code examples
c#uwp-xamlwinui-3

WinUI3: Exception thrown while trying to create a FilePicker


I copied the example code from WinUI3 Gallery, it works perfect in MainWindow, but when I do the same thing in a subpage, I received an Exception. enter image description here I know the problem is with getting the window handle,but I still don't have any idea to solve it.I just wrote the "Hello world" program for C# a few weeks ago, then I got started with WinUI3.

Here is the code

private async void PickAFileButton_Click(object sender, RoutedEventArgs e)
{
    // Clear previous returned file name, if it exists, between iterations of this scenario
    OutputTextBlock.Text = "";

    // Create a file picker
    var openPicker = new Windows.Storage.Pickers.FileOpenPicker();

    // Retrieve the window handle (HWND) of the current WinUI 3 window.
    var window = WindowHelper.GetWindowForElement(this);
    var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(window);

    // Initialize the file picker with the window handle (HWND).
    WinRT.Interop.InitializeWithWindow.Initialize(openPicker, hWnd);

    // Set options for your file picker
    openPicker.ViewMode = PickerViewMode.Thumbnail;
    openPicker.FileTypeFilter.Add("*");

    // Open the picker for the user to pick a file
    var file = await openPicker.PickSingleFileAsync();
    if (file != null)
    {
        PickAFileOutputTextBlock.Text = "Picked file: " + file.Name;
    }
    else
    {
        PickAFileOutputTextBlock.Text = "Operation cancelled.";
}

And in WindowHelper.cs

//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

using Microsoft.UI;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using System;
using System.Collections.Generic;
using WinRT.Interop;

namespace AppUIBasics.Helper
{
    // Helper class to allow the app to find the Window that contains an
    // arbitrary UIElement (GetWindowForElement).  To do this, we keep track
    // of all active Windows.  The app code must call WindowHelper.CreateWindow
    // rather than "new Window" so we can keep track of all the relevant
    // windows.  In the future, we would like to support this in platform APIs.
    public class WindowHelper
    {
        static public Window CreateWindow()
        {
            Window newWindow = new Window();
            TrackWindow(newWindow);
            return newWindow;
        }

        static public void TrackWindow(Window window)
        {
            window.Closed += (sender,args) => {
                _activeWindows.Remove(window);
            };
            _activeWindows.Add(window);
        }

        static public AppWindow GetAppWindow(Window window)
        {
            IntPtr hWnd = WindowNative.GetWindowHandle(window);
            WindowId wndId = Win32Interop.GetWindowIdFromWindow(hWnd);
            return AppWindow.GetFromWindowId(wndId);
        }

        static public Window GetWindowForElement(UIElement element)
        {
            if (element.XamlRoot != null)
            {
                foreach (Window window in _activeWindows)
                {
                    if (element.XamlRoot == window.Content.XamlRoot)
                    {
                        return window;
                    }
                }
            }
            return null;
        }

        static public UIElement FindElementByName(UIElement element, string name)
        {
            if (element.XamlRoot != null && element.XamlRoot.Content != null)
            {
                var ele = (element.XamlRoot.Content as FrameworkElement).FindName(name);
                if (ele != null)
                {
                    return ele as UIElement;
                }
            }
            return null;
        }

        static public List<Window> ActiveWindows { get { return _activeWindows; }}

        static private List<Window> _activeWindows = new List<Window>();
    }
}

UPDATE: Now, I recived this errorenter image description here

------- UPDATE: I rebuild my project and solved this question


Solution

  • My first guess is that, window is null here,

    var window = WindowHelper.GetWindowForElement(this);
    

    and that can be because you didn't use the WindowHelper to create the parent window.

    In App.xaml.cs, instead of

    _window = new MainWindow();
    

    use the WindowHelper to create the window and set the sub page as the Content.

    _window = WindowHelper.CreateWindow();
    _window.Content = new SubPage();
    

    By the way, this way you won't be using the MainWindow class.