2011-12-22 13 views
6

imagine una aplicación wpf donde puedo cambiar dinámicamente el tema. Lo hago intercambiando ResourceDictionaries en el nivel de recursos de la aplicación. Los recursos del tema tienen estilos implícitos definidos para TextBox y similares.Establecer un estilo implícito local diferente de theme-style/alternativo a BasedOn DynamicResource

Ahora tengo una parte en mi aplicación donde los cuadros de texto deben tener este estilo específico "NonDefaultTextBoxStyle" y no el ancho de la aplicación implícita.

Me encantaría hacer esto (usando DynamicResource porque el tema se puede cambiar en tiempo de ejecución):

<StackPanel> 
    <StackPanel.Resources> 
     <Style TargetType="TextBox" BasedOn="{DynamicResource NonDefaultTextBoxStyle}"/> 
    </StackPanel.Resources> 
    <TextBox .../> 
    <TextBox .../> 
    <TextBox .../> 
</StackPanel> 

en lugar de tener que hacer esto:

<StackPanel> 
    <TextBox Style="{DynamicResource NonDefaultTextBoxStyle}" .../> 
    <TextBox Style="{DynamicResource NonDefaultTextBoxStyle}" .../> 
    <TextBox Style="{DynamicResource NonDefaultTextBoxStyle}" .../> 
</StackPanel> 

Ahora simplificar esto, tenía esta idea de establecer una propiedad adjunta heredable en el StackPanel que establecería un estilo específico en cada cuadro de texto descendiente.

¿Es esta una buena idea? ¿Hay formas más simples? ¿Me estoy perdiendo de algo?

esta prácticamente se reduce a: ¿Qué es una alternativa a BasedOn = "{...} DynamicResource en un estilo

Respuesta

4

que tenían el mismo problema pero para ItemsContainerStyle ... Así que lo hice? . más o menos lo que dijo y escribió un AttachedProperty que permitiría a un recurso dinámico para el BasedOn

DynamicResource for Style BasedOn

Aquí está la solución modificada para su situación:

public class DynamicStyle 
{ 
    public static Style GetBaseStyle(DependencyObject obj) 
    { 
     return (Style)obj.GetValue(BaseStyleProperty); 
    } 

    public static void SetBaseStyle(DependencyObject obj, Style value) 
    { 
     obj.SetValue(BaseStyleProperty, value); 
    } 

    // Using a DependencyProperty as the backing store for BaseStyle. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty BaseStyleProperty = 
     DependencyProperty.RegisterAttached("BaseStyle", typeof(Style), typeof(DynamicStyle), new UIPropertyMetadata(DynamicStyle.StylesChanged)); 

    public static Style GetDerivedStyle(DependencyObject obj) 
    { 
     return (Style)obj.GetValue(DerivedStyleProperty); 
    } 

    public static void SetDerivedStyle(DependencyObject obj, Style value) 
    { 
     obj.SetValue(DerivedStyleProperty, value); 
    } 

    // Using a DependencyProperty as the backing store for DerivedStyle. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty DerivedStyleProperty = 
     DependencyProperty.RegisterAttached("DerivedStyle", typeof(Style), typeof(DynamicStyle), new UIPropertyMetadata(DynamicStyle.StylesChanged)); 

    private static void StylesChanged(DependencyObject target, DependencyPropertyChangedEventArgs e) 
    { 
     if (!typeof(FrameworkElement).IsAssignableFrom(target.GetType())) 
      throw new InvalidCastException("Target must be FrameworkElement"); 

     var Element = (FrameworkElement)target; 

     var Styles = new List<Style>(); 

     var BaseStyle = GetBaseStyle(target); 

     if (BaseStyle != null) 
      Styles.Add(BaseStyle); 

     var DerivedStyle = GetDerivedStyle(target); 

     if (DerivedStyle != null) 
      Styles.Add(DerivedStyle); 

     Element.Style = MergeStyles(Styles); 
    } 

    private static Style MergeStyles(ICollection<Style> Styles) 
    { 
     var NewStyle = new Style(); 

     foreach (var Style in Styles) 
     { 
      foreach (var Setter in Style.Setters) 
       NewStyle.Setters.Add(Setter); 

      foreach (var Trigger in Style.Triggers) 
       NewStyle.Triggers.Add(Trigger); 
     } 

     return NewStyle; 
    } 
} 

Y aquí es un ejemplo de su uso:

<!-- xmlns:ap points to the namespace where DynamicStyle class lives --> 
<Button ap:DynamicStyle.BaseStyle="{DynamicResource {x:Type Button}}"> 
    <ap:DynamicStyle.DerivedStyle> 
     <Style TargetType="Button"> 
      <Style.Triggers> 
       <MultiDataTrigger> 
        <MultiDataTrigger.Conditions> 
         <Condition Binding="{Binding Path=FirstButtonWarning}" Value="True"/> 
         <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsEnabled}" Value="True"/> 
        </MultiDataTrigger.Conditions> 
        <MultiDataTrigger.Setters> 
         <Setter Property="Background" Value="{DynamicResource WarningBackground}"/> 
         <Setter Property="Foreground" Value="{DynamicResource WarningForeground}"/> 
        </MultiDataTrigger.Setters> 
       </MultiDataTrigger> 
      </Style.Triggers> 
     </Style> 
    </ap:DynamicStyle.DerivedStyle> 
    <TextBlock Text="Button that changes background and foreground when warning is active"/> 
</Button> 
+0

Sólo puedo animar a leer la pregunta! ¡No estás resolviendo mi problema! –

+0

@ MarkusHütter Ah Veo su pregunta ahora. Bien, continuando con mi respuesta, debería poder cambiar las Propiedades de Dependencias Adheridas en mi solución a 'FrameworkPropertyMetadataOptions.Inherits' (usando este http://msdn.microsoft.com/en-us/library/ms557296.aspx en vez de' UIPropertyMetadata') y luego verifica el tipo de elemento función 'StylesChanged'. La propiedad adjunta solo tendrá que escribirse una vez en el elemento StackPanel. – NtscCobalt

+0

así que te refieres a lo que ya sugerí en la pregunta ... –

3

es lo que realmente necesita ser un DynamicResource?
así que tal vez this le ayudará a

si no es aquí es un ejemplo simple para StaticResource

App.xaml

<Application.Resources> 
     <Style x:Key="myResource" TargetType="Button"> 
      <Setter Property="Background" Value="Black"/> 
      <Setter Property="Foreground" Value="White"/> 
     </Style>   
    </Application.Resources> 

MainWindow.xaml

<StackPanel> 
    <StackPanel.Resources> 
     <Style TargetType="Button" BasedOn="{StaticResource myResource}"/> 
    </StackPanel.Resources> 
    <Button Content="blubb" Height="23" Width="75" /> 
</StackPanel> 

si ambos no le ayuda a que es tal vez podría proporcionar la forma de agregar su recurso

Editar

bien que ahora debe responder a su pregunta

aplicación.xaml

<Application.Resources> 

    <SolidColorBrush x:Key="background" Color="Red" /> 
    <SolidColorBrush x:Key="foreground" Color="Blue" /> 

    <Style x:Key="NonDefaultTextBoxStyle" > 
     <Setter Property="TextBox.Background" Value="{DynamicResource background}"/> 
     <Setter Property="TextBox.Foreground" Value="{DynamicResource foreground}"/> 
    </Style> 

</Application.Resources> 

MainWindow.xaml

<StackPanel> 
    <Button Content="Button" Height="23" Width="75" Click="Button_Click" /> 

    <StackPanel> 
     <StackPanel.Resources> 
      <Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource NonDefaultTextBoxStyle}"> 
      </Style> 
     </StackPanel.Resources> 
     <TextBox Text="bliii" Height="23" Width="75" /> 
     <TextBox Text="blaaa" Height="23" Width="75" /> 
     <TextBox Text="blubb" Height="23" Width="75" /> 
    </StackPanel> 

</StackPanel> 

MainWindow.cs

private void Button_Click(object sender, RoutedEventArgs e) 
     { 
      this.Resources["background"] = Brushes.Black; 
      this.Resources["foreground"] = Brushes.Yellow; 
     } 
+0

Me pregunto por qué esta es la única pregunta que publiqué, ¡donde la gente no lee la pregunta! ¿El tema y el problema son demasiado difíciles de entender? para responderte: sí, debe ser un DynamicResource debido a mi requerimiento de "cambiar dinámicamente el tema" (1ra oración). Si leyeras tu pregunta vinculada, habrás notado que la respuesta es igual a como tu respuesta no usa un recurso dinámico. ¡Lo siento, esto no ayuda! –

+0

@ MarkusHütter lo siento por no leer lo suficiente. Tal vez deberías considerarlo como un punto de mira – WiiMaxx

+0

@ MarkusHütter Creo que mi edición ahora responderá a tu pregunta – WiiMaxx

Cuestiones relacionadas