WinUI3中WindowNative.GetWindowHandle(this)调用崩溃问题求助
解决WinRT.Interop.WindowNative.GetWindowHandle引发的InvalidCastException问题
问题场景
XAML中定义按钮:
<Button x:Name="PickFolderButton" Click="PickFolderButton_Click"/>
对应的后台点击事件代码:
private async void PickFolderButton_Click(object sender, RoutedEventArgs e) { BackupDestinationText.Text = ""; FolderPicker openPicker = new FolderPicker(); var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this); WinRT.Interop.InitializeWithWindow.Initialize(openPicker, hWnd); openPicker.SuggestedStartLocation = PickerLocationId.ComputerFolder; openPicker.FileTypeFilter.Add("*"); StorageFolder folder = await openPicker.PickSingleFolderAsync(); if (folder != null) { StorageApplicationPermissions.FutureAccessList.AddOrReplace("PickedFolderToken", folder); BackupDestinationText.Text = folder.Path; } else { BackupDestinationText.Text = "Operation cancelled"; } }
运行时触发调试中断,错误为System.InvalidCastException(HResult=0x80004002),调用栈指向var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this);这一行。尝试修改App.xaml.cs的m_window字段但无效,因为该字段原本不存在。
错误原因
WinRT.Interop.WindowNative.GetWindowHandle方法要求传入的对象必须是实现了IWindowNative接口的WinRT窗口实例,而你传入的this是页面对象(比如MainPage),页面并没有实现该接口,因此触发类型转换失败的异常。
解决方案
需要获取当前应用的主窗口实例,再调用GetWindowHandle接口,以下是两种可行方式:
方式1:通过App类获取主窗口
如果是WinUI 3应用,先在App.xaml.cs中暴露主窗口属性:
public partial class App : Application { public Window MainWindow { get; private set; } protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args) { MainWindow = new MainWindow(); MainWindow.Activate(); } }
然后在页面的点击事件中修改获取句柄的代码:
// 获取主窗口实例 var mainWindow = (App.Current as App)?.MainWindow; if (mainWindow == null) return; // 获取窗口句柄 var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(mainWindow); WinRT.Interop.InitializeWithWindow.Initialize(openPicker, hWnd);
方式2:通过Application.Current遍历窗口
如果不想修改App类,可以直接从应用的窗口集合中获取第一个窗口:
// 获取应用的主窗口 var mainWindow = Application.Current.Windows.OfType<Window>().FirstOrDefault(); if (mainWindow == null) return; // 获取窗口句柄 var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(mainWindow); WinRT.Interop.InitializeWithWindow.Initialize(openPicker, hWnd);
修改后的完整代码示例
private async void PickFolderButton_Click(object sender, RoutedEventArgs e) { BackupDestinationText.Text = ""; FolderPicker openPicker = new FolderPicker(); // 获取主窗口实例并获取句柄 var mainWindow = Application.Current.Windows.OfType<Window>().FirstOrDefault(); if (mainWindow == null) { BackupDestinationText.Text = "无法获取主窗口"; return; } var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(mainWindow); WinRT.Interop.InitializeWithWindow.Initialize(openPicker, hWnd); openPicker.SuggestedStartLocation = PickerLocationId.ComputerFolder; openPicker.FileTypeFilter.Add("*"); StorageFolder folder = await openPicker.PickSingleFolderAsync(); if (folder != null) { StorageApplicationPermissions.FutureAccessList.AddOrReplace("PickedFolderToken", folder); BackupDestinationText.Text = folder.Path; } else { BackupDestinationText.Text = "Operation cancelled"; } }
内容的提问来源于stack exchange,提问作者lajawi
相关产品推荐
相关产品推荐

