2011-12-22 24 views
6

Immaginare un'applicazione wpf in cui sia possibile modificare dinamicamente il tema. Lo faccio sostituendo ResourceDictionaries al livello di risorsa Application. I resourcedictionaries a tema hanno stili impliciti definiti per TextBox e simili.Impostazione di uno stile implicito locale diverso da stile tema/alternativo a Basato su DynamicResource

Ora ho una parte nella mia applicazione in cui le caselle di testo dovrebbero avere questo stile specifico "NonDefaultTextBoxStyle" e non quello implicito dell'applicazione.

mi piacerebbe fare questo (utilizzando DynamicResource perché il tema può essere modificato durante il runtime):

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

invece di dover fare questo:

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

Ora per semplificare questo, aveva questa idea di impostare una proprietà associata ereditabile sullo StackPanel che avrebbe impostato uno stile specifico su ogni casella di testo discendente.

Questa è una buona idea? Ci sono modi più semplici? Mi sto perdendo qualcosa?

questo si riduce praticamente fino a: Qual è un'alternativa a BasedOn = "{DynamicResource ...} in uno stile

risposta

4

ho avuto lo stesso problema, ma per ItemsContainerStyle ... così ho fatto? . più o meno quello che ha detto e scritto un AttachedProperty che permetterebbe una risorsa dinamica per la BasedOn

DynamicResource for Style BasedOn

Ecco la soluzione modificato per la vostra situazione:

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; 
    } 
} 

E qui è un esempio del suo utilizzo:

<!-- 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

posso solo incoraggiarvi a leggere la domanda! Non stai risolvendo il mio problema! –

+0

@ MarkusHütter Ah Vedo la tua domanda ora. Continuando bene con la mia risposta, dovresti essere in grado di modificare le Proprietà delle dipendenze associate nella mia soluzione a 'FrameworkPropertyMetadataOptions.Inherits' (utilizzando questo http://msdn.microsoft.com/en-us/library/ms557296.aspx invece di' UIPropertyMetadata') e quindi controllare la funzione di tipo 'StylesChanged'. La proprietà allegata dovrà quindi essere scritta una sola volta sull'elemento StackPanel. – NtscCobalt

+0

quindi intendi quello che ho già suggerito nella domanda ... –

3

fa davvero bisogno di essere un DynamicResource?
così forse this vi aiuterà a

se non qui è un semplice esempio per 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> 

se entrambi non l'aiuto di voi forse si potrebbe offrire come si aggiunge il Resource

Modifica

ok che dovrebbe ora rispondere alla tua domanda

App.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

Mi chiedo perché questa è l'unica domanda che ho postato, in cui le persone non leggono la domanda! L'argomento e il problema sono troppo difficili da capire? per risponderti: sì, deve essere un DynamicResource a causa della mia esigenza di "modificare dinamicamente il tema" (1a frase). Se avessi letto la tua domanda collegata, avresti notato che la risposta come la tua risposta non utilizza una risorsa dinamica. Mi dispiace, questo non aiuta! –

+0

@ MarkusHütter mi dispiace per non leggere abbastanza a fondo. Forse dovresti metterlo in evidenza come eye catcher – WiiMaxx

+0

@ MarkusHütter penso che il mio Edit ora risponda alla tua domanda – WiiMaxx

Problemi correlati