ちょっと迷ったのでメモしておきます。
C+/WinRT自体についてはこちら
上のドキュメントの、このページの部分に関連してます。
Step 1: Windows Runtime Component プロジェクトの作成と idl の定義
Windows Runtime Component (C++/WinRT) のプロジェクトを作成します。今回は名前は MyComponents にしました。
Class.idl があるのですが、これは消します。
そして Person.idl を作成するのと Person.h と Person.cpp も作成します。
Person.idl に Person クラスを定義します。
namespace MyComponents
{
runtimeclass Person : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
Person();
String Name;
}
}
インテリセンスとかないので辛いです。
Step 2: Person クラスの作成
idl を書いてビルドしてプロジェクトのすべてのファイルを表示すると Person.g.h と Person.g.cpp が生成されています。

ここには winrt::MyComponents::implementation::Person_base クラスと、その別名の winrt::MyComponents::implementation::PersonT と、winrt::MyComponents::factory_implementation::PersonT が定義されています。この PersonT という名前の 2 つのクラスを継承して Person クラスを自分のコードに追加します。
Person.h は以下のような感じになります。
#pragma once #include "Person.g.h" // 生成されたヘッダーを include namespace winrt::MyComponents::implementation { struct Person : PersonT<Person> { }; } namespace winrt::MyComponents::factory_implementation { struct Person : PersonT<Person, implementation::Person> { }; }
PersonT とか Person とか同じ名前が出てきますが、これは名前空間が違うので気を付けてみましょう。
Step 3: Person クラスの実装
Person クラスの中を作っていきます。idl ファイルに定義していた Name プロパティと INotifyPropertyChanged の実装をします。Person.h に、ここらへんを追加していきましょう。
#pragma once #include "Person.g.h" // 生成されたヘッダーを include namespace winrt::MyComponents::implementation { struct Person : PersonT<Person> { Person() = default; winrt::hstring Name() const; void Name(winrt::hstring const& name); winrt::event_token PropertyChanged(winrt::Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler); void PropertyChanged(winrt::event_token const& token); private: winrt::hstring _name; winrt::event<winrt::Windows::UI::Xaml::Data::PropertyChangedEventHandler> _propertyChanged; }; } namespace winrt::MyComponents::factory_implementation { struct Person : PersonT<Person, implementation::Person> { }; }
Person.cpp に実装を書いていきます。頭にお決まりの include を書いて namespace を定義したらヘッダーに戻って実装したいメソッドで Ctrl + . で以下のように、いい感じにひな型が作られます。
#include "pch.h" #include "Person.h" #include "Person.g.cpp" // 自動生成された cpp を include namespace winrt::MyComponents::implementation { winrt::hstring Person::Name() const { return winrt::hstring(); } void Person::Name(winrt::hstring const& name) { } winrt::event_token Person::PropertyChanged(winrt::Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler) { return winrt::event_token(); } void Person::PropertyChanged(winrt::event_token const& token) { } }
中身を実装してこんな感じ。
#include "pch.h" #include "Person.h" #include "Person.g.cpp" // 自動生成された cpp を include namespace winrt::MyComponents::implementation { winrt::hstring Person::Name() const { return _name; } void Person::Name(winrt::hstring const& name) { _name = name; _propertyChanged(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs(L"Name")); } winrt::event_token Person::PropertyChanged(winrt::Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler) { return _propertyChanged.add(handler); } void Person::PropertyChanged(winrt::event_token const& token) { _propertyChanged.remove(token); } }
Step 4: C# から使う
C# の UWP アプリを作ります。ここでは CSharpUWPApp にしました。
CSharpUWPApp から MyComponents に参照設定を追加します。ここらへんは普通の C# のクラスライブラリ使うときと一緒ですね。という`か、ちゃんと C++/WinRT で Windows ランタイムコンポーネントが定義出来ていれば C# から使うのは普通の C# のクラスを使うときと変わりありません。
ということで MainPage.xaml.csでPerson` クラスをプロパティに持たせて…
using MyComponents; using Windows.UI.Xaml.Controls; // The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409 namespace CSharpUWPApp { /// <summary> /// An empty page that can be used on its own or navigated to within a Frame. /// </summary> public sealed partial class MainPage : Page { private Person Person { get; } = new Person { Name = "Tanaka" }; public MainPage() { this.InitializeComponent(); } } }
MainPage.xaml で適当にバインドしましょう。
<Page x:Class="CSharpUWPApp.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:CSharpUWPApp" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <StackPanel> <TextBox Text="{x:Bind Person.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> <TextBlock Text="{x:Bind Person.Name, Mode=OneWay}" /> </StackPanel> </Page>
実行するとちゃんと使えています。

まとめ
ハイパフォーマンスで美しい Windows Runtime Component を C++/WinRT で!!…作れるようになる道のりは自分にとってははるか長いように見える。 がんばろっと。
ソースコードはこちら。