I'm writing WinUI 3 and UWP code, and I want to have a custom control with a DependencyProperty on it:
<local:MyControl Foo="Bar" />
I've read Custom dependency properties on MSDN, but there's a lot of content there. What's a short example with the minimum needed to implement a custom DependencyProperty in UWP or WinUI XAML, using C++/WinRT?
Here's my distillation of Custom dependency properties, which is worth reading anyway since it explains a lot of the nuances of Dependency Properties:
FooProperty
of type static Microsoft.UI.Xaml.DependencyProperty
Foo
of the actual type you want.// MyControl.idl
runtimeclass MyControl : Microsoft.UI.Xaml.Controls.UserControl
{
MyControl(); // ... etc
// Add these for each property
static Microsoft.UI.Xaml.DependencyProperty FooProperty{ get; };
String Foo;
}
DependencyObject::GetValue
and SetValue
(which should be inherited via UserControl etc).Register
your Dependency Property.// MyControl.h
namespace winrt::MyAppNamespace::implementation
{
struct MyControl : MyControlT<MyControl>
{
// ...
static winrt::Microsoft::UI::Xaml::DependencyProperty FooProperty() const noexcept
{
return s_FooProperty;
}
auto Foo() const noexcept
{
return winrt::unbox_value<winrt::hstring>(GetValue(FooProperty()));
}
void Foo(winrt::hstring const& value)
{
SetValue(FooProperty(), winrt::box_value(value));
}
private:
static winrt::Microsoft::UI::Xaml::DependencyProperty s_FooProperty;
}
}
// MyControl.cpp
using namespace winrt::MyAppNamespace::implementation;
MyControl::s_FooProperty =
winrt::Microsoft::UI::Xaml::DependencyProperty::Register(
L"Foo",
winrt::xaml_typename<winrt::hstring>(),
winrt::xaml_typename<winrt::MyAppNamespace::MyControl>(),
winrt::Microsoft::UI::Xaml::PropertyMetadata{nullptr});
Done! You now have a working dependency property:
<MyControl Foo="Bar!" />
PropertyMetadata
constructor.// Value-changed callback
MyControl::s_FooProperty =
winrt::Microsoft::UI::Xaml::DependencyProperty::Register(
L"Foo",
winrt::xaml_typename<winrt::hstring>(),
winrt::xaml_typename<winrt::MyAppNamespace::MyControl>(),
winrt::Microsoft::UI::Xaml::PropertyMetadata{nullptr, &MyControl::OnFooChanged});
// Value-changed callback & default value
MyControl::s_FooProperty =
winrt::Microsoft::UI::Xaml::DependencyProperty::Register(
L"Foo",
winrt::xaml_typename<winrt::hstring>(),
winrt::xaml_typename<winrt::MyAppNamespace::MyControl>(),
winrt::Microsoft::UI::Xaml::PropertyMetadata{winrt::box_value(L"Default value"), &MyControl::OnFooChanged});
Note that the callback is static, not a member function. You'll have to fetch the actual instance:
/*static*/ void MyControl::OnFooChanged(winrt::Microsoft::UI::Xaml::DependencyObject const& d, winrt::Microsoft::UI::Xaml::DependencyPropertyChangedEventArgs const& e)
{
auto control{ d.as<MyAppNamespace::MyControl>() };
auto newValue{ winrt::unbox_value<winrt::hstring>(e.NewValue()) };
}