Metro: Overriding/inheriting build-in styles

4 posts, 0 answers
  1. Marc
    Marc avatar
    88 posts
    Member since:
    Jul 2011

    Posted 11 Nov 2011 Link to this post

    Let's say I created a default style for ScrollViewer based on the provided metro style like this:

    <Style x:Key="DefaultScrollViewer" TargetType="ScrollViewer" Telerik:StyleManager.BasedOn="Metro">
      <Setter Property="Background" Value="MySuperSexyColor" />
    </Style>
    <Style BasedOn="{StaticResource DefaultScrollViewer}" TargetType="ScrollViewer" />

    Now, ScrollViewer is a control that it used in many of Telerik's control templates, e.g. in the ControlTemplate for ListBox. This is the source of your ListBoxStyle:

    <Style TargetType="ListBox">
      <Setter Property="Padding" Value="1" />
      ...
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="ListBox">
            <Border  ...>
              <ScrollViewer x:Name="ScrollViewer"
                Margin="0"
                telerik:StyleManager.Theme="{StaticResource Theme}"
                Padding="{TemplateBinding Padding}"
                Background="{TemplateBinding Background}">
                <ItemsPresenter />
              </ScrollViewer>
            </Border>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>

    As you can see, the control template sets the attached Theme-property for the internal ScrollViewer. Briefly looking at the source code of this attached property, it seems like this is getting the control's (ScrollViewer in this case) Telerik style from the theme (Metro in this case) via GetThemeStyle() and - if not null - applies it. The problem is, that this circumvents the default style for ScrollViewer which I set above and always uses the built-in Telerik style. So I never see "MySuperSexyColor" for the ScrollViewer used in a ListBox. If you would omit the attached Theme property in the control template (e.g. you've done that in the RadWatermarkTextBox control template), MY default style for ScrollViewer would be used in the ListBox. At least that's what my tests say...

    Am I correct? Is this the intended behaviour? If yes, how can I adjust the controls used in your control template without copying one billion lines of XAML (can't say how much I hate this) just to change one property? I even tried the evil way of modifiying the internal cached resources dictionary of the theme via reflection to add my dictionary so that the style lookup could find mine. But this is not possible in Silverlight due to access restrictions.

    Thank you,
    Stephan
  2. Kalin Milanov
    Admin
    Kalin Milanov avatar
    447 posts

    Posted 17 Nov 2011 Link to this post

    Hello Stephan,

    There might be another way of getting the styles to work without the need of re-templating the your whole project.

    In your Silverlight installation folder you will find a folder named Themes. In it there are the styles for all out themes (pure XAML). What you can do is add the project to your solution and use a project reference to that theme instead of the DLL. Then you can simply style the ScrollViewer directly in the theme and its style will be applied automatically to all our controls. This way you will also separate your styles from your logic which in theory will make the product you are working on more manageable.

    There is a shortcoming however and it is entirely our fault. While I was trying to prepare a sample to show you what I mean I discovered that there is a bug in the Themes projects and you will get a runtime exception. This is something we will be fixing.

    So in the meantime what you started as an approach is the best one until we fix this.
    I apologize for the trouble and the late reply.

    Best wishes,
    Kalin Milanov
    the Telerik team

    Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>

  3. Marc
    Marc avatar
    88 posts
    Member since:
    Jul 2011

    Posted 17 Nov 2011 Link to this post

    Thank you Kalin for your response, I really appreciate that.

    The solution you proposed is one of many I already tried last week. Unfortunately, I wasn't able to build the metro theme with the provided themes project. I found another post somewhere here where one of your colleagues mentioned that the project seems to be broken for the metro theme (in contrast to the other themes all xaml files are located in the "bin" folder). That's where I stopped trying to change/compile the provided theme. I didn't like the approach anyway since I find it quite intrusive and it enforces me to diff the whole stuff whenever you update the "original" metro theme.

    The way I do it now is to inherit from the controls that need customization in order to provide a clean and consistent look. Then I override OnApplyTemplate and use various Helper/Extension classes I wrote over the last week to modify/fix/improve/extend the original metro control themes and their storyboards. Actually it was quite time-consuming and it's not an optimal solution but the best and cleanest I came up with. Now I can see all the things I changed within a view lines of code. The customizations are furthermore only applied if the metro theme is set as the current application theme and the internal control in question is indeed found in the template. I can even all customizations off with just a single boolean flag. Still, whenever you provide a new improved/more consistent/fixed version of metro I have to go over my customized classes to see if they still do what they are supposed to do. However, I think this is still better to go over a few lines of code than diffing one billion xaml files.

    Here is an example from one of my a customizations:

    public class XTextBox : RadWatermarkTextBox
    {
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
     
            var customizer = new Customizer(this, GetTemplateChild);
            customizer.ApplyToChild<ContentControl>("WatermarkVisualElement",
                child =>
                {
                    child.Foreground = LaF.TextBrush50;
                    child.IsTabStop = false;
                });
            customizer.ApplyToChild<Border>("DisabledVisualElement",
                child => child.Visibility = Visibility.Collapsed);
            customizer.ApplyToStoryboard("CommonStates", "Disabled",
                new DoubleAnimation { To = 0.5 }, "ContentElement", "Opacity");
            customizer.ApplyToStoryboard("CommonStates", "ReadOnly",
                storyboard => storyboard.RemoveAnimations("Border"));
        }
    }

    And here this is how it looks now with your default metro colors (I actually use a slightly different palette in my application). See attachement...

    Cheers,
    Stephan


    PS: I would be great if the metro theme would look like this out of the box. ;-) I'm sure it will in the next release or the one afterwards, right?

  4. Pana
    Admin
    Pana avatar
    748 posts

    Posted 23 Nov 2011 Link to this post

    Hello Stephan,

    The Metro theme files are now on their place with the release of Q3. As for the theme inconsistencies we are constantly working on improving our controls.

    All the best,
    Pana
    the Telerik team
    Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>
Back to Top