Why is Resource Dictionary a Sealed Class?

JKayJKay USMember ✭✭✭

Why is Resource Dictionary a Sealed Class?

It means I cannot do

<ResourceDictionary>
   <Style>
   ...
   </Style>
</ResourceDictionary>

Any valid reason or is it a bug that needs reporting to Bugzilla?

Answers

  • ChaseFlorellChaseFlorell CAInsider, University mod
    edited September 2015

    On your page, you'll do something like.

      <ContentPage.Resources>
        <ResourceDictionary>
         <Style>
         ...
         </Style>
        </ResourceDictionary>
      </ContentPage.Resources>
    

    Similarily, you can do it at the application level and share it with all your pages.

    app.xaml

      <Application.Resources>
        <ResourceDictionary>
    
          <Color x:Key="PrimaryDarkGray">#666666</Color>
    
          <Style x:Key="Foo" TargetType="Layout">
            <Setter Property="BackgroundColor" Value="{StaticResource PrimaryDarkGray}" />
            <Setter Property="Opacity" Value="0.95" />
          </Style>
        </ResourceDictionary>
      </Application.Resources>
    

    somepage.xaml

       <BoxView Style="{StaticResource Foo}" />
    
  • JKayJKay USMember ✭✭✭
    edited September 2015

    @ChaseFlorell But if I don't want the ResourceDictionary on a page it means I can't create my own ResourceDictionary as a workaround I did have to add the Resources to a page and Retrieve them.

    Background info

    I was trying to add Application.Resources to an Mvvmcross application. MvvmCross application relies on you building a MvxApplication (Which doesnt inherit from Application) meaning you do not have an Application.Resources property for your application (Can't put them in the App.xaml class)

    You can however use Xamarin.Forms.Application.Current.Resources = new MyResourceDictionary();

    But you can't create your own Xaml resource dictionary because it is a Sealed class.

    What I infact had to do was create a dummy ContentPage with Resources as you have shown and do a for loop on the Resources adding them to my own Resource Dictionary..

    Was just wondering whether there was any valid reason as to why it was a Sealed class

  • ChaseFlorellChaseFlorell CAInsider, University mod

    I understand your dilemma now (it wasn't clear in the original question). I too tried the same thing and hit a wall. I simply wanted to create a ResourceDictionary.xaml page... and you're right, we cannot.

    I do know from a number of months ago that the X.F team wants to un-seal the majority of the API, but they will only do so when they feel it's in a finished state, which makes sense.

    I'm not sure if I'd throw it up on Bugzilla, but definitely on UserVoice.

  • ChaseFlorellChaseFlorell CAInsider, University mod

    Voted!

  • adamkempadamkemp USInsider, Developer Group Leader mod

    I think you're mixing up some terms here. In C# sealed just means you can't create subclasses. It doesn't mean you can't create instances using the constructor. As long as the type has a public constructor (which this one does) you can create instances of it using new, and then you can add things to it. You can also create one in XAML anywhere that a ResourceDictionary is supported. I even just tested making a new class that has a Styles property of type ResourceDictionary, and I created that ResourceDictionary within a XAML file. All of that works. So what specifically are you trying that doesn't work?

  • JKayJKay USMember ✭✭✭
    edited October 2015

    @adamkemp I understand C# but what I was trying to do was:

    Xaml

    <ResourceDictionary x:class="MyApp.MyStyles">
       <Style x:Key="MyStyle" TargetType="Label">
             <Setter Property="TextColor" Value="Green">
       </Style>
    </ResourceDictionary>
    

    Code behind

    public class MyStyles : ResourceDictionary
    {
           public MyStyles() { }
    }
    

    Which isn't allowed due to the fact ResourceDictionary is sealed. My question is WHY is this class sealed. I see no logical reason as to why you would label this class as sealed

    But maybe creating another class with a ResourceDictionary property rather than inheriting is a better idea

  • adamkempadamkemp USInsider, Developer Group Leader mod

    My question is why are you trying to subclass ResourceDictionary? What are you adding to it? Why not just do this?

    <ResourceDictionary>
       <Style x:Key="MyStyle" TargetType="Label">
             <Setter Property="TextColor" Value="Green">
       </Style>
    </ResourceDictionary>
    

    I don't understand what problem you are trying to solve by subclassing.

  • ChaseFlorellChaseFlorell CAInsider, University mod
    edited October 2015

    Essentially it would be awesome to be able to add this to the App.xaml

        <Application.Resources>
            <resources:MyColors /> <!-- references MyColors.xaml -->
            <resources:MyStyles />  <!-- references MyStyles.xaml -->
        </Application.Resources>
    

    MyColors.xaml

    <ResourceDictionary xmlns="xmlns="http://xamarin.com/schemas/2014/forms"
                                       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                                       x:Class="MyNamespace.Resources.MyColors">
        <Color x:Key="PrimaryBlue">#004B85</Color>
    </ResourceDictionary>
    

    Instead of 300 lines of styles and colors

  • adamkempadamkemp USInsider, Developer Group Leader mod
    edited October 2015

    The custom class isn't accomplishing anything for that use case. You're just describing having multiple instances of resource dictionaries that you can merge together. The feature you're missing for that is merged resource dictionaries, which WPF and other Microsoft XAML variants have but Xamarin.Forms doesn't.

    Even if you could make a custom subclass this XAML syntax wouldn't work:

    <Application.Resources>
        <resources:MyColors /> <!-- references MyColors.xaml -->
        <resources:MyStyles />  <!-- references MyStyles.xaml -->
    </Application.Resources>
    

    Because the Application.Resources property is a single ResourceDictionary, and it would throw an exception if you try to put multiple objects in that property. The way it would need to work using merged resource dictionaries is like this:

    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="MyColors.xaml" />
                <ResourceDictionary Source="MyStyles.xaml" />
            </ResourceDictionary.MergedDictionaries> 
        </ResourceDictionary>
    </Application.Resources>
    

    Again, none of that requires custom subclasses of ResourceDictionary, but it does require the MergedDictionaries property to exist.

    Sadly, Xamarin developers have said they have no plans to support that. I just created this UserVoice topic for it so you can go vote for that and encourage others to do so.

  • ChaseFlorellChaseFlorell CAInsider, University mod
    edited October 2015

    Ah, I hadn't looked that deeply at The Resources vs ResourceDictionary bit (and have actually never done pure MS Xaml before)... but you're right. I can't vote on your UV, but I did comment.

  • DavidStrickland0DavidStrickland0 USMember ✭✭✭
    edited October 2015

    That would be great. Be pretty easy to implement that functionality. You'd just have to create a class add the MergedDictionaries collection property, inherit from ResourceDictionary and .....

    However this still wouldn't fix the ops issue since he doesn't have an Application.Resources

    <ContentPage.Resources>
        <ResourceDictionary="MyColors.xaml" />
    </ContentPage.Resources>
    

    Would however resolve his issue and of course we could do that in code behind now if
    .... wait for it ...
    ResourceDictionary wasn't sealed.

    ContentPage.Resources = new ResourceDictionary()

    would of course work but get us nowhere to read our XAML we'd need to use

    ContentPage.Resource = new myResourceDictionary()

    or have access to the internal xaml parser so we could.

    ContentPage.Resource = XAMLReader.Read("MyColors.xaml");

    which to me might be an even better UserVoice Option.

  • adamkempadamkemp USInsider, Developer Group Leader mod

    David, if Forms had merged dictionaries then you could do this:

    <ContentPage.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="MyColors.xaml" />
                <ResourceDictionary Source="MyStyles.xaml" />
            </ResourceDictionary.MergedDictionaries> 
        </ResourceDictionary>
    </ContentPage.Resources>
    

    You could also write a XAML file like this (MyCustomResources.xaml):

    <ResourceDictionary xmlns="xmlns="http://xamarin.com/schemas/2014/forms"
                                       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="MyColors.xaml" />
            <ResourceDictionary Source="MyStyles.xaml" />
        </ResourceDictionary.MergedDictionaries>
        <!-- other resources -->
    </ResourceDictionary>
    

    And then you could reference it the same way:

    <ContentPage.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="MyCustomResources.xaml" />
            </ResourceDictionary.MergedDictionaries> 
        </ResourceDictionary>
    </ContentPage.Resources>
    

    Again, none of that requires a custom subclass. I can't think of any use cases for custom subclasses of ResourceDictionary, especially not the ones given in this thread. Merged resource dictionaries are the way to support composable XAML resources in every other XAML framework. They're very powerful.

  • DavidStrickland0DavidStrickland0 USMember ✭✭✭
    edited October 2015

    Valid use Case for Custom Subclass of ResourceDictionary= Implementation of MergedDictionaries.

    If ResourceDictionary wasn't sealed you'd have MergedDictiinaries because me,you or any number of coders on the forum would have written it already.

  • adamkempadamkemp USInsider, Developer Group Leader mod

    I suppose that's a fair point, but it would still be mooted if you already had that feature, which was the premise I was starting with when I said I couldn't think of a use case. So can you think of any other use cases?

    The fact is that there is some advantage to not having to worry about subclasses. It might be cheaper for them to give us the one feature we actually need than to unseal the class and try to handle all the other possible cases. Personally I would much prefer that they implement merged dictionaries as a first class concept rather than the community having to do it.

Sign In or Register to comment.