Custom attached property of ResourceDictionary wit

2019-09-09 13:22发布

问题:

As you know a FrameworkElement has a property of type ResourceDictionary named Resources, in XAML we can declare it easily like this:

 <FrameworkElement.Resources>
     <SomeObject x:Key="someKey"/>
     <SomeOtherObject x:Key="someOtherKey"/>
 </FrameworkElement.Resources>

It's some kind of implicit syntax, all the elements declared inside will be added to the ResourceDictionary. Now I would like to create an attached property having type of ResourceDictionary, of course a requirement of being notified when the property is changed is needed. Here is the code:

public static class Test
{
    public static readonly DependencyProperty TestProperty =
        DependencyProperty.RegisterAttached("Test", typeof(ResourceDictionary), 
                         typeof(Test), new PropertyMetadata(propertyChanged));
    public static ResourceDictionary GetTest(DependencyObject o)
    {
        return o.GetValue(TestProperty) as ResourceDictionary;
    }
    public static void SetTest(DependencyObject o, ResourceDictionary resource)
    {
        o.SetValue(TestProperty, resource);
    }
    static void propertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
    {

    }
}

Usage in XAML:

<Grid>
    <local:Test.Test>
        <Style TargetType="Button" x:Key="cl"></Style>
    </local:Test.Test>
</Grid>

Now if I run the code, an exception will be thrown saying Test property is null. I've tried providing a default instance for the attached property like this:

public static readonly DependencyProperty TestProperty =
        DependencyProperty.RegisterAttached("Test", typeof(ResourceDictionary), 
        typeof(Test), new PropertyMetadata(new ResourceDictionary(), propertyChanged));

Then it seems to run OK but there is not any change notification initially. It's very important to get the change notification at first so that I can proceed some handling.

Currently to achieve what I want, I have to let the default value as null and use it in XAML like this:

<local:Test.Test>
   <ResourceDictionary>
      <Style TargetType="Button" x:Key="cl"></Style>
   </ResourceDictionary>
</local:Test.Test>

That works but not very convenient, I would like it to behave like what we can do with the Resources property of FrameworkElement. I hope someone here has some suggestion to solve this issue. I would be highly appreciated to receive any idea even something saying it's impossible (but of course you should be sure about that).