locked
override style ignored by Generic.xaml RRS feed

  • Question

  • My generic.xaml code in the Assembly1:

     <Style x:Key="myLabelStyle" TargetType="{x:Type Label}"> 
        <Setter Property="Foreground" Value="Red"/> 
        <Setter Property="Content" Value="generic"/> 
     </Style> 
     
     <ControlTemplate x:Key="theButton" TargetType="{x:Type local:MyButton}"> 
        <Grid Background="Beige"> 
            <ContentPresenter/> 
            <Label Style="{DynamicResource myLabelStyle}"/> 
        </Grid> 
    </ControlTemplate> 
     
    <Style x:Key="{x:Type local:MyButton}" TargetType="{x:Type local:MyButton}"> 
        <Setter Property="Template" Value="{StaticResource theButton}"/> 
    </Style> 
    

    Assembly2 references Assembly1 and the used ResourceDicitonary contains following code:

    <Style x:Key="myLabelStyle" TargetType="{x:Type Label}"> 
        <Setter Property="Foreground" Value="Blue"/> 
        <Setter Property="Content" Value="coool"/> 
    </Style> 
    

    If I execute the application all works fine. The label contains "coool" and its blue.

    So for test purposes I commented out all the xaml definition listed above in the Assembly2. The idea is, to test if the generic.xaml is used as fallback.

    It is used, but the label is empty and so it has no color. If I change in the generic.xaml from Style="{DynamicResource myLabelStyle}" to Style="{StaticResource myLabelStyle}"/>

     <ControlTemplate x:Key="theButton" TargetType="{x:Type local:MyButton}"> 
        <Grid Background="Beige"> 
            <ContentPresenter/> 
            <Label Style="{StaticResource myLabelStyle}"/> 
        </Grid> 
     </ControlTemplate> 
    

    then is the label red and contains the content "generic". The problem is as soon as I use my style override in Assembly2. It has no effect. The label is still red and not blue as expected.

    Both assemblies have the following assembly setting:

    [assembly: ThemeInfo( 
    ResourceDictionaryLocation.SourceAssembly, //where theme specific resource dictionaries are located 
    //(used if a resource is not found in the page,  
    // or application resource dictionaries) 
    ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 
    //(used if a resource is not found in the page,  
    // app, or any theme specific resource dictionaries) 
    

    )]

    Why wpf behaves that way, any idea?

    Saturday, August 7, 2010 9:00 PM

Answers

  • Hi Marinko,

    I performed a test based on your sample code and did see the problem on my side.

    The reason of this problem is that the StaticResource Markup Extension and DynamicResource Markup Extenstion process resource key differently.

    The StaticResource Markup Extension processes a key by looking up the value for that key in all available resource dictionaries. This happens during loading, which is the point in time when the loading process needs to assign the property value that takes the static resource reference. The DynamicResource Markup Extension instead processes a key by creating an expression, and that expression remains unevaluated until the application is actually run, at which time the expression is evaluated and provides a value.

    In your scenario, when DynamicResource Markup Extension is used, only an expression is created when the MyButton is being loaded and this expression isn't evaluated until the MyButton is being presented on a Window. At this point, DynamicResource Markup Extension couldn't find the resource with the key of "myLabelStyle" if there's only a resource with the key of "myLabelStyle" is defined in the Generic.xaml within Assembly 1.

    If you want to provide default property values on the Label in the ControlTemplate of the MyButton, you can bind the properties of the Label to the properties on the MyButton and set the default property values on the MyButton in the style for MyButton in the Generic.xaml. Set the properties values on the MyButton instance when used on a Window to override the default property values. For example:

    <ControlTemplate x:Key="theButton" TargetType="{x:Type local:MyButton}"> 
       
    <Grid Background="Beige"> 
           
    <ContentPresenter/> 
           
    <Label Foreground="{TemplateBinding LabelForeground}" Content="{TemplateBinding LabelContent}"/> 
       
    </Grid> 
    </ControlTemplate>

    <Style x:Key="{x:Type local:MyButton}" TargetType="{x:Type local:MyButton}"> 
       
    <Setter Property="Template" Value="{StaticResource theButton}"/> 
        <Setter Property="LabelForeground" Value="Red"/>
        <Setter Property="LabelContent" Value="generic"/>
    </Style> 

    public class MyButton : Control
        {
            static MyButton()
            {
                DefaultStyleKeyProperty.OverrideMetadata(typeof(MyButton), new FrameworkPropertyMetadata(typeof(MyButton)));           
            }

            public Brush LabelForeground
            {
                get { return (Brush)GetValue(LabelForegroundProperty); }
                set { SetValue(LabelForegroundProperty, value); }
            }

            // Using a DependencyProperty as the backing store for LabelForeground.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty LabelForegroundProperty =
                DependencyProperty.Register("LabelForeground", typeof(Brush), typeof(MyButton), new UIPropertyMetadata(null)); 

            public object LabelContent
            {
                get { return (object)GetValue(LabelContentProperty); }
                set { SetValue(LabelContentProperty, value); }
            }

            // Using a DependencyProperty as the backing store for LabelContent.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty LabelContentProperty =
                DependencyProperty.Register("LabelContent", typeof(object), typeof(MyButton), new UIPropertyMetadata(null));


        }

    When used on a Window:

     <custom:CustomControl1 LabelContent="coool" LabelForeground="Blue"/>

    For more information on resources in WPF, please read the following MSDN document:

    "Resources Overview"
    http://msdn.microsoft.com/en-us/library/ms750613.aspx

    Hope this helps.
    If you have any question, please feel free to let me know.

    Sincerely,
    Linda Liu

    MSDN Subscriber Support in Forum 
    If you have any feedback on our support, please contact msdnmg@microsoft.com


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.

    • Marked as answer by Marinko Babic Thursday, August 12, 2010 7:02 AM
    Monday, August 9, 2010 6:18 AM

All replies

  • Hi Marinko,

    I performed a test based on your sample code and did see the problem on my side.

    The reason of this problem is that the StaticResource Markup Extension and DynamicResource Markup Extenstion process resource key differently.

    The StaticResource Markup Extension processes a key by looking up the value for that key in all available resource dictionaries. This happens during loading, which is the point in time when the loading process needs to assign the property value that takes the static resource reference. The DynamicResource Markup Extension instead processes a key by creating an expression, and that expression remains unevaluated until the application is actually run, at which time the expression is evaluated and provides a value.

    In your scenario, when DynamicResource Markup Extension is used, only an expression is created when the MyButton is being loaded and this expression isn't evaluated until the MyButton is being presented on a Window. At this point, DynamicResource Markup Extension couldn't find the resource with the key of "myLabelStyle" if there's only a resource with the key of "myLabelStyle" is defined in the Generic.xaml within Assembly 1.

    If you want to provide default property values on the Label in the ControlTemplate of the MyButton, you can bind the properties of the Label to the properties on the MyButton and set the default property values on the MyButton in the style for MyButton in the Generic.xaml. Set the properties values on the MyButton instance when used on a Window to override the default property values. For example:

    <ControlTemplate x:Key="theButton" TargetType="{x:Type local:MyButton}"> 
       
    <Grid Background="Beige"> 
           
    <ContentPresenter/> 
           
    <Label Foreground="{TemplateBinding LabelForeground}" Content="{TemplateBinding LabelContent}"/> 
       
    </Grid> 
    </ControlTemplate>

    <Style x:Key="{x:Type local:MyButton}" TargetType="{x:Type local:MyButton}"> 
       
    <Setter Property="Template" Value="{StaticResource theButton}"/> 
        <Setter Property="LabelForeground" Value="Red"/>
        <Setter Property="LabelContent" Value="generic"/>
    </Style> 

    public class MyButton : Control
        {
            static MyButton()
            {
                DefaultStyleKeyProperty.OverrideMetadata(typeof(MyButton), new FrameworkPropertyMetadata(typeof(MyButton)));           
            }

            public Brush LabelForeground
            {
                get { return (Brush)GetValue(LabelForegroundProperty); }
                set { SetValue(LabelForegroundProperty, value); }
            }

            // Using a DependencyProperty as the backing store for LabelForeground.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty LabelForegroundProperty =
                DependencyProperty.Register("LabelForeground", typeof(Brush), typeof(MyButton), new UIPropertyMetadata(null)); 

            public object LabelContent
            {
                get { return (object)GetValue(LabelContentProperty); }
                set { SetValue(LabelContentProperty, value); }
            }

            // Using a DependencyProperty as the backing store for LabelContent.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty LabelContentProperty =
                DependencyProperty.Register("LabelContent", typeof(object), typeof(MyButton), new UIPropertyMetadata(null));


        }

    When used on a Window:

     <custom:CustomControl1 LabelContent="coool" LabelForeground="Blue"/>

    For more information on resources in WPF, please read the following MSDN document:

    "Resources Overview"
    http://msdn.microsoft.com/en-us/library/ms750613.aspx

    Hope this helps.
    If you have any question, please feel free to let me know.

    Sincerely,
    Linda Liu

    MSDN Subscriber Support in Forum 
    If you have any feedback on our support, please contact msdnmg@microsoft.com


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.

    • Marked as answer by Marinko Babic Thursday, August 12, 2010 7:02 AM
    Monday, August 9, 2010 6:18 AM
  • Hi Marinko,

    How about the problem now?

    If you have any question, please feel free to let me know.

    Sincerely,
    Linda Liu


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Wednesday, August 11, 2010 7:29 AM
  • Hi Linda

    Static Resource is evaluated during load and Dynamic Resource expression remains unevaluated until the application is actually run. Let's make my example a little bit simpler by just using one assemlby:

    My generic.xaml code in the Assembly1:

     <Style x:Key="myLabelStyle" TargetType="{x:Type Label}"> 
     <Setter Property="Foreground" Value="Red"/> 
     <Setter Property="Content" Value="generic"/> 
     </Style> 
     
     <ControlTemplate x:Key="theButton" TargetType="{x:Type local:MyButton}"> 
     <Grid Background="Beige"> 
      <ContentPresenter/> 
      <Label Style="{DynamicResource myLabelStyle}"/> 
     </Grid> 
    </ControlTemplate> 
     
    <Style x:Key="{x:Type local:MyButton}" TargetType="{x:Type local:MyButton}"> 
     <Setter Property="Template" Value="{StaticResource theButton}"/> 
    </Style>

    In this case the all the code above is in the generic.xamlof the Assembly1. There are no other ResourceDictionaries. Why is the DynamicResource myLabelStyle totally ignored during the loading process?

    Sincerely,
    Marinko

    • Edited by Marinko Babic Wednesday, August 11, 2010 9:27 PM code style
    Wednesday, August 11, 2010 9:26 PM
  • Hi Marinko,

    Thank you for your reply!

    > Why is the DynamicResource myLabelStyle totally ignored during the loading process?

    The reason is the difference behavior of StaticResource Markup Extension and DynamicResource Markup Extension as I have mentioned in my first reply.

    It's a good practice to use StaticResource Markup Extension in the styles which are in system scope.

    Sincerely,
    Linda Liu


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Thursday, August 12, 2010 6:45 AM