【问题标题】:C++/WinRT KeyDown event handler not being added in release mode未在发布模式下添加 C++/WinRT KeyDown 事件处理程序
【发布时间】:2020-09-03 06:33:07
【问题描述】:

我正在尝试对开源 Microsoft Terminal application 进行一些更改。

我正在向现有文本框添加 KeyDown 事件侦听器。

当我使用 Debug 配置运行应用程序时,一切都按预期运行,但是当我在 Release 下运行相同的代码时,KeyDown 事件处理程序不会添加到控件中。

我正在运行:Release、x64、CascadiaPackage。


这是添加 KeyUp 处理程序的原始代码:

    // Tab.cpp (original)
    Controls::TextBox tabTextBox;
    
    // ...

    tabTextBox.KeyUp([weakThis](const IInspectable& sender, Input::KeyRoutedEventArgs const& e) {
        auto tab{ weakThis.get() };
        auto textBox{ sender.try_as<Controls::TextBox>() };
        if (tab && textBox)
        {
            // handle keyup event
        }
    });

以下是我将KeyDown 处理程序添加到同一控件的方式:

    // Tab.cpp (edited)
    auto sawKeyDown = false;
    
    /*
    !!! This event handler works in Debug but doesn't exist when run in Release configuration !!!
    */
    tabTextBox.KeyDown([&sawKeyDown](const IInspectable&, Input::KeyRoutedEventArgs const&) {
        sawKeyDown = true;
    });
    // !!!
    
    tabTextBox.KeyUp([weakThis, &sawKeyDown](const IInspectable& sender, Input::KeyRoutedEventArgs const& e) {
        auto tab{ weakThis.get() };
        auto textBox{ sender.try_as<Controls::TextBox>() };
        if (tab && textBox && sawKeyDown)
        {
            // ... original code here...
        }

        sawKeyDown = false;
    });

如果我尝试在发布模式下的事件处理程序中添加断点,Visual Studio 会在断点图标上显示此消息:

当前不会命中断点。没有调试器目标代码类型的可执行代码与此行相关联。 可能的原因包括:条件编译、编译器优化或当前调试器代码类型不支持此行的目标架构。

位置:Tab.cpp,第 716 行('_ConstructTabRenameBox(const winrt::hstring& tabText)')


是否出于某种原因优化了代码 KeyDown 侦听器?或者我还需要做些什么来将事件侦听器添加到文本框。

我尝试在 KeyDown 处理程序中引用 weakThis,但更改代码似乎没有任何效果。

【问题讨论】:

  • 请问您是如何判断KeyDown事件处理程序没有添加到控件中的?您在发布模式下的事件处理程序中添加了一个断点,断点没有被触发或其他?因为当我尝试在 KeyDown 事件中更改文本框的文本时,它在调试和发布模式下都可以正常工作。
  • 与您的问题无关,在TextBox 中注册关键事件可能选择了错误的抽象级别。 TextBox字符进行操作,并且大量处理将键盘输入转换为字符。注册关键事件是对所有处理的回避,并最终导致重新实现它。你没有这样做。例如,如果用户按下 [Shift]+A,则您实现的逻辑不能代表这种情况(即同时按下多个键)。
  • Faywang-MSFT 两件事: 1. sawKeyDown 值未设置为 true,这在调试模式下确实发生; 2. 当我在 KeyDown 监听器中设置断点时,Visual Studio 显示消息The breakpoint will not currently be hit. No executable code of the debugger's target code type is associated with this line.(也在我的问题中列出)。在调试模式下,我可以在处理程序中设置一个断点,一切都按预期工作。
  • 您是否使用调试符号编译发布配置?您是否设置了/Zo 编译器选项?
  • 该 lambda 是否试图修改堆栈上的局部变量?连接处理程序的方法将在您的 lambda 被调用之前返回,从而导致严重的内存损坏。

标签: visual-c++ winrt-xaml c++-winrt windows-terminal


【解决方案1】:

我相信Ryan Shepherd's comment 显示了导致问题的原因。

sawKeyDown 变量是在堆栈上本地定义的,这意味着在调用 lambda 时它不再存在(糟糕!)。

解决方案是将标志设为成员变量。

    // file.h - define the member variable inside the struct/type
    bool _receivedKeyDown{ false };
    // file.cpp
    tabTextBox.KeyDown([weakThis](const IInspectable&, Input::KeyRoutedEventArgs const&) {
        auto tab{ weakThis.get() };
        tab->sawKeyDown = true;
    });
    
    tabTextBox.KeyUp([weakThis](const IInspectable& sender, Input::KeyRoutedEventArgs const& e) {
        auto tab{ weakThis.get() };
        auto textBox{ sender.try_as<Controls::TextBox>() };
        if (tab && textBox && tab->sawKeyDown)
        {
            // ... original code here...
        }

        tab->sawKeyDown = false;
    });

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-05-01
    • 1970-01-01
    • 2023-04-04
    • 2011-04-25
    • 2022-01-19
    • 1970-01-01
    • 2010-12-04
    • 2012-09-02
    相关资源
    最近更新 更多