当我在页面上将 NavigationCacheMode 设置为“启用”或“必需”时,导航到页面然后返回时,我会从
System.StackOverflowException
获得 CallWindowProc
。
在我的应用程序中,我有一个
ToggleButton
,可以通过 F6 键切换,效果非常好。我需要添加一个新的 Windows 过程来执行使用 CallWindowProc
的操作,并且当启用 System.StackOverflowException
时它会给我 NavigationCacheMode
。我需要 NavigationCacheMode
来保存我的按钮所处的状态。
我使用 Visual Studio 2022 和空白应用程序,打包(桌面中的 WinUI 3)并安装了 CsWin32 软件包。
MainPage.xaml
:
<?xml version="1.0" encoding="utf-8" ?>
<Page
x:Class="NavigationProc.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:NavigationProc"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
NavigationCacheMode="Enabled"
mc:Ignorable="d">
<!-- NavigationCacheMode being set to Enabled causes the app to crash -->
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center"
Orientation="Horizontal">
<ToggleButton x:Name="ToggleButton">F6</ToggleButton>
<Button Click="Button_Click">To go page</Button>
</StackPanel>
</Page>
MainPage.xaml.cs
:
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using System;
using System.Runtime.InteropServices;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.UI.Input.KeyboardAndMouse;
using Windows.Win32.UI.WindowsAndMessaging;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace NavigationProc;
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
public MainPage()
{
InitializeComponent();
Loaded += MainPage_Loaded;
}
private WNDPROC? origHotKeyProc;
private WNDPROC? hotKeyProcD;
private LRESULT HotKeyProc(HWND hWnd, uint Msg, WPARAM wParam, LPARAM lParam)
{
uint WM_HOTKEY = 0x0312; // HotKey Window Message
if (Msg == WM_HOTKEY)
{
if (ToggleButton.IsEnabled)
{
ToggleButton.IsChecked = !ToggleButton.IsChecked;
}
}
return PInvoke.CallWindowProc(origHotKeyProc, hWnd, Msg, wParam, lParam);
}
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
// Get window handle
MainWindow window = App.MainWindow;
HWND hWnd = new(WinRT.Interop.WindowNative.GetWindowHandle(window));
// Register hotkey
int id = 0x0000;
_ = PInvoke.RegisterHotKey(hWnd, id, HOT_KEY_MODIFIERS.MOD_NOREPEAT, 0x75); // F6
// Add hotkey function pointer to window procedure
hotKeyProcD = HotKeyProc;
IntPtr hotKeyProcPtr = Marshal.GetFunctionPointerForDelegate(hotKeyProcD);
IntPtr wndPtr = PInvoke.SetWindowLongPtr(hWnd, WINDOW_LONG_PTR_INDEX.GWL_WNDPROC, hotKeyProcPtr);
origHotKeyProc = Marshal.GetDelegateForFunctionPointer<WNDPROC>(wndPtr);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
_ = Frame.Navigate(typeof(OtherPage));
}
}
private bool IsHotKeyRegistered { get; set; }
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
if (IsHotKeyRegistered is true)
{
return;
}
IsHotKeyRegistered = true;
...
}