ThemeResource failed to assign to custom property
Describe the bug
I have a custom templated control, and I want to bind its property to a ThemeResource, and I got crash at xaml loading phase during app launch.
Steps to reproduce the bug
- Create a new WinUI3 C++ packaged project
- Create a new templated control, with this idl
[default_interface]
runtimeclass MyControl : Microsoft.UI.Xaml.Controls.Control
{
MyControl();
String StringProperty;
}
- In
MainWindow.xaml, use this code
<Grid>
<Grid.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Light">
<x:String x:Key="MyStringResource">Light</x:String>
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<x:String x:Key="MyStringResource">Dark</x:String>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</Grid.Resources>
<local:MyControl StringProperty="{ThemeResource MyStringResource}" />
</Grid>
- Build and run, see the crash
Expected behavior
No response
Screenshots
NuGet package version
WinUI 3 - Windows App SDK 1.6 Preview 1: 1.6.240807006-preview1
Windows version
Windows 11 (22H2): Build 22621
Additional context
Making it to a DependencyProperty does not solve this issue.
I tried and this issue also happens in UWP too.
Repro
Making it to a
DependencyPropertydoes not solve this issue.
The target property does need to be a DependencyProperty in order to style it with {ThemeResource}. What error did you hit when it was a DP?
Making it to a
DependencyPropertydoes not solve this issue.The target property does need to be a
DependencyPropertyin order to style it with{ThemeResource}. What error did you hit when it was a DP?
Same exception. The getter function of that DependencyProperty does not even get called before the exception.
DependencyProperty requires some work to register, which I'm not sure if you did. See: https://learn.microsoft.com/windows/uwp/xaml-platform/custom-dependency-properties
@codendone I figured out what's wrong here. I registered the DependencyProperty as a function local static, that is
winrt::Microsoft::UI::Xaml::DependencyProperty MyControl::StringPropertyProperty()
{
static auto s_stringPropertyProperty =
winrt::Microsoft::UI::Xaml::DependencyProperty::Register(
L"StringProperty",
winrt::xaml_typename<winrt::hstring>(),
winrt::xaml_typename<class_type>(),
nullptr
);
return s_stringPropertyProperty;
}
This will cause the exception. But if I register it as a class static, it will work
struct MyControl : MyControlT<MyControl>
{
MyControl() = default;
winrt::hstring StringProperty() { return L""; }
void StringProperty(winrt::hstring value){}
static winrt::Windows::UI::Xaml::DependencyProperty StringPropertyProperty();
static winrt::Windows::UI::Xaml::DependencyProperty s_stringPropertyProperty;
};
Can you please confirm this is an expected behavior?
The only change to get it working was pulling the variable out to a class static? I wouldn't expect that to make a difference, as long as the DependencyProperty::Register() call still happens before the property is needed and the right parameters are passed.
The only change to get it working was pulling the variable out to a class static? I wouldn't expect that to make a difference, as long as the DependencyProperty::Register() call still happens before the property is needed and the right parameters are passed.
Please take a look at this. The first approach (I commented them) will work. The second will not.