0%

WinUI3使用FilePicker和FolderPicker

微软已经在2023年2月的社区电话会议上公布更新了WinUI 3 Gallery中的示例,如果你安装了WinUI 3 Gallery,可以点击FilePicker跳转。

但是微软示例的做法并不一定适合直接拿来用,尤其是在获取HWND这里,并没有解释存在的坑。如果官方示例不能成功运行可以参考我这篇博客,他们的原理是相同的。

桌面应用需要获取HWND

在基于桌面的应用程序(如WinUI3或WPF MSIX)中,FileOpenPickerFileSavePickerFolderPickerAPI需要与它们关联的HWND,以便它们知道要在哪个窗口上显示。 这意味着,与UWP不同,您必须在使用FilePicker和FolderPicker之前添加几行额外的代码。

一般情况下,我们在UWP当中这样使用FileOpenPicker()

1
2
3
var filePicker = new FileOpenPicker();
filePicker.FileTypeFilter.Add("*");
var file = await filePicker.PickSingleFileAsync();

但是,对于桌面程序,必须添加两行以获取当前的HWND,并在Picker上设置HWND:

1
2
3
4
5
6
7
8
9
10
11
var filePicker = new FileOpenPicker();

// 通过传入Window对象获取当前窗口的HWND
var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(this);

// 将HWND与文件选择器相关联
WinRT.Interop.InitializeWithWindow.Initialize(filePicker, hwnd);

// 像往常一样使用Picker
filePicker.FileTypeFilter.Add("*");
var file = await filePicker.PickSingleFileAsync();

如何在Page中使用Picker

获取一个HWND并设置给Picker很简单,但是问题在于上面这些都只适用于在MainWindow上使用。

然而,大多数应用程序都是在Page中实现逻辑,MainWindows只是一个没有任何逻辑实现的容器。

如何解决也很简单,我们只需要将:

1
GetWindowHandle(this)

替换为:

1
GetWindowHandle(App.m_window)

这里面的App.m_window是在App.xaml.cs中定义的。但如果你在一个空白的WinUI3中这么用,VS会提示你App.m_window有一定的保护级别,这是因为m_window默认定义为:

1
private Window m_window;

我们需要将其修改为:

1
public static Window m_window;

static是HWND调用所需。

参考资料

1、How to use FilePicker and FolderPicker in WinUI 3 and other desktop-based apps · Issue #1188 · microsoft/WindowsAppSDK (github.com)

2、【WinUI 3】获取MainWindow、AppWindow、WindowHandle、WindowID实例_获取app.window的classname_XiaoLi8848的博客-CSDN博客