2011-12-22 16 views
6

Wyobraź sobie aplikację wpf, w której mogę dynamicznie zmieniać motyw. Robię to, zamieniając ResourceDictionaries na poziomie zasobów aplikacji. Kompozycje tematyczne mają niejawne style zdefiniowane dla TextBox i tym podobne.Ustawianie lokalnego domyślnego stylu różniącego się od stylu kompozycji/alternatywy do BasedOn DynamicResource

Teraz mam część w mojej aplikacji, w której pola tekstowe powinny mieć ten specyficzny styl "NonDefaultTextBoxStyle", a nie szeroki, domyślny program.

chciałbym to zrobić (przy użyciu DynamicResource ponieważ motyw można zmienić w trakcie wykonywania):

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

zamiast to zrobić:

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

teraz, aby uprościć to ja wpadł na pomysł ustawienia dziedziczonej właściwości na StackPanel, która ustawiłaby określony styl na każdym kolejnym polu tekstowym.

Czy to dobry pomysł? Czy są prostsze sposoby? Czy czegoś brakuje?

to dość dużo sprowadza się do: Co jest alternatywą dla basedon = "{...} DynamicResource w stylu

Odpowiedz

4

miałem dokładnie ten sam problem, ale dla ItemsContainerStyle ... tak zrobiłem? . prawie co powiedział i napisał AttachedProperty który pozwoliłby dynamiczny zasób dla basedon

DynamicResource for Style BasedOn

Oto rozwiązanie zmodyfikowane do sytuacji:

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

I tu jest przykładem jego zastosowania:

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

mogę jedynie zachęcić do zapoznania się pytanie! Nie rozwiązujesz mojego problemu! –

+0

@ MarkusHütter Ah Widzę teraz twoje pytanie. Hmm dobrze kontynuując moją odpowiedź, powinieneś być w stanie zmienić Attached Dependencies Properties w moim rozwiązaniu na 'FrameworkPropertyMetadataOptions.Inherits' (używając tego http://msdn.microsoft.com/en-us/library/ms557296.aspx zamiast' UIPropertyMetadata'), a następnie sprawdź funkcję typu 'StylesChanged'. Załączona właściwość będzie musiała zostać zapisana tylko raz na elemencie StackPanel. – NtscCobalt

+0

więc masz na myśli to, co już zasugerowałem w pytaniu ... –

3

robi to naprawdę trzeba być DynamicResource?
więc może this pomoże Ci

jeśli nie tu to prosty przykład dla 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> 

gdy oba nie pomoże to ty może można dostarczyć jak dodać zasób

Edycja

ok że powinien teraz odpowiedzieć na pytanie

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

Zastanawiam się, dlaczego to jest jedyne pytanie, które napisałem, gdzie ludzie nie czytają pytania! Czy temat i problem są zbyt trudne do zrozumienia? aby ci odpowiedzieć: tak, musi to być DynamicResource z powodu mojego wymogu "dynamicznej zmiany tematu" (pierwsze zdanie). Gdybyś przeczytał swoje powiązane pytanie, zauważyłbyś, że odpowiedź tak, jak twoja odpowiedź nie używa dynamicznego zasobu. Bardzo mi przykro, to nie pomaga! –

+0

@ MarkusHütter Przepraszamy, nie czyta wystarczająco dokładnie. Może powinieneś odważyć go jako przyciągającego wzrok – WiiMaxx

+0

@ MarkusHütter myślę, że moja edycja będzie teraz odpowiadać na twoje pytanie – WiiMaxx

Powiązane problemy