Search code examples
c++mvvmuwpc++-winrt

How to share a view model in C++ UWP?


How can I share a view model between different pages in a C++ UWP application?


This answer is a C# solution which uses a static property:

public sealed partial class MainPage : Page
{
    public AppViewModel ViewModel { get; set; } = new AppViewModel();
    public static MainPage Current { get; set; }

    public MainPage()
    {
        this.InitializeComponent();
        Current = this;
    }
}

But I am having trouble translating that into C++.

My C++ MainPage currently looks like this:

namespace winrt::myproject::implementation
{
    struct MainPage : MainPageT<MainPage>
    {
        MainPage();

        myproject::MainViewModel MainViewModel() const { return this->mainViewModel; }

    private:
        myproject::MainViewModel mainViewModel{ nullptr };
    };
}

The view model instance is created in the MainPage() constructor using

this->mainViewModel = winrt::make<myproject::implementation::MainViewModel>();

And the .idl file simply lists the view model instance as a property:

[default_interface]
runtimeclass MainPage : Windows.UI.Xaml.Controls.Page
{
    MainPage();

    MainViewModel MainViewModel{ get; };
}

How can I share the MainViewModel between all of my pages?

  • What do I need to change in the .idl and in the .h file?

  • Do I need to use std::shared_ptr<myproject::MainViewModel> or winrt::comptr<myproject::MainViewModel> to avoid copying the struct and to really share the same instance?


Solution

  • myproject::MainViewModel ultimately derives from winrt::Windows::Foundation::IUnknown. It is this structure that implements all the reference counting machinery, turning each derived type into a shared pointer to its interface.

    The following implementation

    myproject::MainViewModel MainViewModel() const { return this->mainViewModel; }
    

    invokes the IUnknown::IUnknown(IUnknown const& other) copy-c'tor that increments the reference count on other and constructs an IUnknown instance holding the same pointer. Both this->mainViewModel and the return value point to the same object.

    In general, copying structures that represent projected types performs a shallow copy. Only the pointer to the object is copied, and the reference count is incremented. Like a std::shared_ptr the operation is thread-safe and has comparable overhead.

    A lot more information on the internals and use of projected types can be found at Consume APIs with C++/WinRT.