将 C++/CX 中的 "delegate" 对象转换为其在 C++/WinRT 中的等效对象

3

我是WinRT的新手。我正在将我的使用C++/CX编写的Windows UWP应用程序转换成C++/WinRT。我有一个C++/CX ref类,其基本上执行与C#中Microsoft.VisualStudio.PlatformUI.DelegateCommand类相同的操作。我的C++类实现了ICommand接口,其中ExecuteCanExecute回调由委托处理。头文件的简略代码如下:

public delegate void ExecuteDelegate(Platform::Object^ parameter);
public delegate bool CanExecuteDelegate(Platform::Object^ parameter);

public ref class DelegateCommand sealed :
    Windows::UI::Xaml::DependencyObject,
    Windows::UI::Xaml::Data::INotifyPropertyChanged,
    public Windows::UI::Xaml::Input::ICommand
{
public:
    DelegateCommand(ExecuteDelegate^ execute, CanExecuteDelegate^ canExecute);
    .
    .
    .
private:
    ExecuteDelegate^       m_executeDelegate = nullptr;
    CanExecuteDelegate^    m_canExecuteDelegate = nullptr;
    .
    .
    .
};

我的 DelegateCommand 类的典型实例从一个拥有 ExecuteCanExecute 方法实现的类中,将一个弱指针和函数指针传递到构造函数中:

Commands::Instance->UndoCommand = ref new DelegateCommand(
    ref new ExecuteDelegate(this, &SVGDocumentUserControl::ExecuteUndoCommand),
    ref new CanExecuteDelegate(this, &SVGDocumentUserControl::CanExecuteUndoCommand));

我相信这是一个简单的问题,但从我的阅读中并不清楚,那么如何在C++/WinRT中定义两个C++/CX委托?

public delegate void ExecuteDelegate(Platform::Object^ parameter);
public delegate bool CanExecuteDelegate(Platform::Object^ parameter);

[编辑:我也在思考如何在*.idl文件中定义构造函数指针。]
感谢您的耐心等待。

只是一个想法,当您将现有的代码提供给C++/CX编译器时,它不能以一种方式导出元数据(我猜这将是winmd格式),让您看到正确的原始声明吗? - Ben Voigt
@BenVoigt:我在我的CX应用程序的*.winmd文件上运行了winmdidl.exe。但是我需要的那些部分,特别是委托定义,并不在其中。虽然想法不错。 - Escovado
据我所知,你的C++/CX代码确实会生成一个.winmd文件。如果是这样,你可以使用C++/WinRT的cppwinrt.exe来处理该.winmd文件,并让它生成相应的头文件。这样就可以获得完整的声明,包括委托。 - IInspectable
还有一个关于委托的部分,可能也会有所帮助,那就是从C++/CX转移到C++/WinRT。链接在这里:https://learn.microsoft.com/en-us/windows/uwp/cpp-and-winrt-apis/move-to-winrt-from-cx - IInspectable
@IInspectable 我读了关于委托的那一节。我希望我是错的,但它似乎没有涵盖我正在尝试使用它们的方式。我刚刚在*.winmd文件上尝试了cppwinrt.exe。我收到了错误消息:“找不到类型“Windows.UI.Xaml.FlowDirection”。是否有包含/库目录应该添加到开发者控制台命令行?谢谢。 - Escovado
显示剩余2条评论
1个回答

4

我看到你的代码把delegates定义为公共类型(而不是内部类型)。所以,假设你确实需要它们成为你组件的公开API的一部分,那么你只需在MIDL3中定义你的delegates(同时定义一个测试类并接受这些delegates作为构造函数参数,如下:

namespace BlankApp1
{
    delegate void ExecuteDelegate(Object param);
    delegate Boolean CanExecuteDelegate(Object param);

    [default_interface]
    runtimeclass TestClass
    {
        TestClass(ExecuteDelegate execute, CanExecuteDelegate canExecute);
    }
}

接着,你可以为这些委托投影出类型,并利用C++/WinRT为委托提供的全部丰富支持。例如,TestClass 的实现很简单:

struct TestClass : TestClassT<TestClass>
{
    TestClass() = default;
    TestClass(BlankApp1::ExecuteDelegate const& execute, BlankApp1::CanExecuteDelegate const& canExecute)
        : m_execute(execute)
        , m_canExecute(canExecute)
    {}

private:
    ExecuteDelegate m_execute;
    CanExecuteDelegate m_canExecute;
};

使用C++/WinRT丰富的委托支持实例化该类型很容易,并且将为您提供与C++/CX相同的生命周期安全语义(即,存储对象的弱引用以及其成员函数指针)。

struct MyClass : winrt::implements<MyClass, winrt::Windows::Foundation::IInspectable>
{
    MyClass() = default;

    void Execute(winrt::Windows::Foundation::IInspectable const&)
    {
    }

    bool CanExecute(winrt::Windows::Foundation::IInspectable const&)
    {
        return true;
    }

    TestClass CreateCommand()
    {
        return TestClass{
            ExecuteDelegate{ get_weak(), &MyClass::Execute },
            CanExecuteDelegate{ get_strong(), &MyClass::CanExecute }
        };
    }
};

1
成功了。在*.idl文件中正确声明委托是让我困惑的原因。而且它们在我直接使用的源代码中是不可见的。谢谢。现在我可以开始工作了! - Escovado

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接