2009-01-04 8 views
29

Ich versuche, ein benutzerdefiniertes Steuerelement zu erstellen - eine Schaltfläche - die abhängig vom Wert einer Eigenschaft im Datenkontext auf mehrere Stile angewendet wird.Bindung für WPF-Stile

Was ich dachte, ist etwas ähnliches mit:

<Button Style="{Binding Path=ButtonStyleProperty, Converter={StaticResource styleConverter}}" Text="{Binding Path=TextProp}" /> 

Und in Code ... ein IValueConverter implementieren, die unten etwas ähnlich den Code funktioniert in der ConvertTo Methode:

switch(value as ValueEnums) 
{ 
    case ValueEnums.Enum1: 
     FindResource("Enum1ButtonStyle") as Style; 
    break; 

    ... and so on. 
} 

Allerdings bin ich mir nicht sicher, wie ich das Style-Objekt herausziehen soll und auch wenn das überhaupt möglich ist ...

Was mache ich in t Er bedeutet, dass die Zeit das Ereignis DataContextChanged behandelt und dann einen Handler an das PropertyChanged-Ereignis des Objekts anfügt, das an die Schaltfläche gebunden ist - und dann die switch-Anweisung dort ausführen.

Es ist nicht ganz perfekt, aber bis ich eine bessere Lösung finden kann, scheint es, dass ich das verwenden muss.

Antwort

35

Wenn Sie den ganzen Stil (und nicht nur Teile davon) ersetzen wollen, dann werden Sie wahrscheinlich werden diese Stile in Ressourcen gespeichert.

<Button> 
    <Button.Style> 
     <MultiBinding Converter="{StaticResource StyleConverter}"> 
      <MultiBinding.Bindings> 
       <Binding RelativeSource="{RelativeSource Self}"/> 
       <Binding Path="MyStyleString"/> 
      </MultiBinding.Bindings> 
     </MultiBinding> 
    </Button.Style> 
</Button> 

Durch ein Multibinding mit und Selbst als der wir dann in unserer Konverter Ressourcen Nachschlag erste Bindung mit: Sie sollten etwas entlang der Linien zu tun in der Lage sein. Der Konverter benötigt IMultiValueConverter (statt IValueConverter) zu implementieren und wie folgt aussehen kann:

class StyleConverter : IMultiValueConverter 
{ 
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     FrameworkElement targetElement = values[0] as FrameworkElement; 
     string styleName = values[1] as string; 

     if (styleName == null) 
      return null; 

     Style newStyle = (Style)targetElement.TryFindResource(styleName); 

     if (newStyle == null) 
      newStyle = (Style)targetElement.TryFindResource("MyDefaultStyleName"); 

     return newStyle; 
    } 

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 

Es ist nicht etwas, was ich sehr oft tun, aber das aus dem Gedächtnis funktionieren sollte :)

+0

Danke Steve - das tat genau das, was ich versuchte zu tun :) –

+0

Keine Sorge. Wie bei allem in WPF, gibt es wahrscheinlich noch 10 Wege, aber dieser Weg scheint ziemlich sauber und "Designer freundlich" :) –

+0

Danke! Ich habe versucht, etwas in diese Richtung für einen StringToStyle-Konverter herauszufinden und stieß auf das, was super funktionierte. – Rachel

14

Es scheint, dass Sie DataTrigger Klasse verwenden müssen. Es ermöglicht Ihnen, basierend auf dem Inhalt verschiedene Stile auf Ihre Schaltfläche anzuwenden.

Zum Beispiel Stil folgenden wird Schaltfläche Hintergrund Eigenschaft auf rot basierend auf dem Wert der Daten-Eigenschaft des Kontextobjekts

<Style x:Key="ButtonStyle" TargetType="{x:Type Button}"> 
    <Style.Triggers> 
     <DataTrigger Binding="{Binding Path="Some property"}" 
        Value="some property value"> 
      <Setter Property="Background" Value="Red"/> 
     </DataTrigger> 
    </Style.Triggers> 
</Style> 
+0

Während Sie sich mit der Lage sein Stile anwenden, basierend auf den Daten von der gebundene Kontext würde ich lieber nur Stile völlig wechseln - sonst werden sie zu vermischten ... –

8

Für diejenigen von uns, kann nicht Multi-Wert-Konverter verwenden (ich schaue dir SL4 und WP7 :), dank Steven's Antwort fand ich einen Weg mit einem gewöhnlichen Wert-Konverter.

Die einzige Annahme ist, dass der Stilwert in der Eigenschaft des zu setzenden Stils enthalten ist.

Wenn Sie also das MVVM-Muster verwenden, wird angenommen, dass der Stilwert (z. B. TextSmall, TextMedium, TextLarge) Teil des Ansichtsmodells ist, und Sie müssen nur den Konverterparameter übergeben, der den Namen definiert von Stil.

Zum Beispiel sagen, dass Ihre Ansicht Modell Eigenschaft hat:

public string ProjectNameStyle 
{ 
    get { return string.Format("ProjectNameStyle{0}", _displaySize.ToString()); } 
} 

Anwendung Stil:

<Application.Resources> 
    <Style x:Key="ProjectNameStyleSmall" TargetType="TextBlock"> 
     <Setter Property="FontSize" Value="40" /> 
    </Style> 
    <Style x:Key="ProjectNameStyleMedium" TargetType="TextBlock"> 
     <Setter Property="FontSize" Value="64" /> 
    </Style> 
    <Style x:Key="ProjectNameStyleLarge" TargetType="TextBlock"> 
     <Setter Property="FontSize" Value="90" /> 
    </Style> 

XAML-Ansicht:

<TextBlock 
     Text="{Binding Name}" 
     Style="{Binding ., Mode=OneWay, Converter={cv:StyleConverter}, ConverterParameter=ProjectNameStyle}"> 

Mit Ihrer StyleConverter Klasse IValueConverter Umsetzung:

Beachten Sie, dass dies der WPF-Code ist, da der Konverter aus einer MarkupExtension und einem IValueConverter abgeleitet ist. t existieren.

Hoffe, dass jemand hilft, und nochmals vielen Dank Steven!

1

Ansichtsmodell

private Style _dynamicStyle = (Style)Application.Current.FindResource("Style1"); 
     public Style DynamicStyle 
     { 
      get { return _dynamicStyle; } 
      set 
      { 
       _dynamicStyle = value; 
       OnPropertyChanged("DynamicStyle"); 
      } 

     } 

public event PropertyChangedEventHandler PropertyChanged; 

    private void OnPropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 

eine Eigenschaft in Ihrem Ansichtsmodell implementieren und dann dynamisch Stil ändern, wo immer Sie wie unten wollen.

DynamicStyle=(Style)Application.Current.FindResource("Style2");// you can place this code where the action get fired 

Ansicht

gesetzt Dann Datacontext Wert und dann den folgenden Code in Ihrer Ansicht implementieren

<Button Style="{Binding DynamicStyle,Mode=TwoWay}"/> 
+0

Ist dies keine Verletzung des MVVM-Patterns? Da der vm jetzt einen Stil kennt. –