microsoft / microsoft-ui-xaml

Windows UI Library: the latest Windows 10 native controls and Fluent styles for your applications
MIT License
6.36k stars 678 forks source link

Subclassing Microsoft.UI.Xaml.Window causes all xaml event handlers not working with C++WinRT #9031

Open HO-COOH opened 1 year ago

HO-COOH commented 1 year ago

Describe the bug

I subclass (inherit) Microsoft.UI.Xaml.Window to add some custom logic. The project builds and runs, and the controls are there. But all event handlers defined in Xaml (like Button Click) failed to execute.

This only happens in C++/WinRT. C# project works fine.

Steps to reproduce the bug

  1. Subclass Microsoft.UI.Xaml.Window, here is the idl

    namespace WinUI3Cpp
    {
    [Microsoft.UI.Xaml.Data.Bindable]  //I guess it was because the default bindable attribute issue, but nope
    [default_interface]
    unsealed runtimeclass WindowEx : Microsoft.UI.Xaml.Window
    {
        WindowEx();
    
        Boolean IsShownInSwitchers;
    }
    }
  2. Change the class of MainWindow.xaml
    <?xml version="1.0" encoding="utf-8"?>
    <local:WindowEx
    ...>
    <Button Click="Button_Click">Click</Button>
    </local:WindowEx>
  3. Change MainWindow.idl
    import "WindowEx.idl";
    namespace WinUI3Cpp
    {
    [default_interface]
    runtimeclass MainWindow : WinUI3Cpp.WindowEx
    {
        MainWindow();
    }
    }
  4. Put a break point in the button click handler. Build and run the project. The break point is not hit.

Expected behavior

No response

Screenshots

No response

NuGet package version

WinUI 3 - Windows App SDK 1.4.2: 1.4.231008000

Windows version

Windows 10 (1809): Build 17763

Additional context

No response

DarranRowe commented 1 year ago

Do you see the same issue if you just use Window in your Xaml file?

https://github.com/microsoft/microsoft-ui-xaml/assets/52577874/80d34335-0d4b-4e63-8fc7-134c5f01711e

Following your instructions as closely as I could, I didn't see anything like you described. I did, however, have this WindowEX separated out in a separate WinRT component.

HO-COOH commented 1 year ago

@DarranRowe Now things get interesting. I tried separated out the WindowEx class into a winrt component project and things indeed worked. You can reproduce my issue if you don't separate it out.

And to answer your question, as I said I need to add custom logic to my WindowEx class (extra properties), so I need to use it as the root window object in Xaml.

DarranRowe commented 1 year ago

One thing that I did notice is that if the extended window type is defined in the executable, the generated code has it specifying WindowEX in the list of implemented types:

//MainWindow.xaml.g.h
...
namespace winrt::CmpTest2::implementation
{
    using IInspectable = ::winrt::Windows::Foundation::IInspectable;

    template <typename D, typename ... I>
    struct MainWindowT : public ::winrt::CmpTest2::implementation::MainWindow_base<D,
        ::winrt::CmpTest2::implementation::WindowEX,
        I...>
...

However, when it is in a separate component, then this doesn't occur:

//MainWindow.xaml.g.h
...
namespace winrt::CmpTest::implementation
{
    using IInspectable = ::winrt::Windows::Foundation::IInspectable;

    template <typename D, typename ... I>
    struct MainWindowT : public ::winrt::CmpTest::implementation::MainWindow_base<D,
        ::winrt::Microsoft::UI::Xaml::Markup::IComponentConnector,
        I...>
...

There is also that lack of IComponentConnector and this seems to be the problem.

JaiganeshKumaran commented 1 year ago

the generated code has it specifying WindowEX in the list of implemented types:

@DarranRowe This is expected since when the base class is in a different component, the actual implementation type is not accessible to you.

HO-COOH commented 4 months ago

This is still an issue today, and I am still not able to inherit a custom Window (defined within in the same project) and have to rewrite quite a lot of logic