I'm trying to create a custom control - a button - which will have multiple styles applied to it depending on the value of a property within the data context.
What I was thinking is using something similar to:
<Button Style="{Binding Path=ButtonStyleProperty, Converter={StaticResource styleConverter}}" Text="{Binding Path=TextProp}" />
And in code... Implement an IValueConverter which does something similar to the code below in the ConvertTo
method:
switch(value as ValueEnums) { case ValueEnums.Enum1: FindResource("Enum1ButtonStyle") as Style; break; ... and so on. }
However I'm not entirely sure about how to pull out the style object and even if this is possible at all...
What I am doing in the mean time is handling the DataContextChanged
event, then attaching a handler to the PropertyChanged
event of the object being bound to the button - then running the switch statement in there.
Its not quite perfect but until I can find a better solution it seems like that is what I'll have to use.
To apply the style, set the Style property on the element to the x:Key value, using a StaticResource markup extension, as shown here. Notice that the first TextBlock element has the style applied to it while the second TextBlock element remains unchanged.
To apply the multiple styles as you phrase it above, the best bet is to use triggers. In future version of WPF, the VisualStateManager will be introduced which supports the visual state transition between different set of setters, triggers, and animations which could enable a broader styling scenarios.
If you want to replace the whole style (rather than just elements of it) then you'll probably be storing those styles in resources. You should be able to do something along the lines of:
<Button> <Button.Style> <MultiBinding Converter="{StaticResource StyleConverter}"> <MultiBinding.Bindings> <Binding RelativeSource="{RelativeSource Self}"/> <Binding Path="MyStyleString"/> </MultiBinding.Bindings> </MultiBinding> </Button.Style> </Button>
By using a MultiBinding and using Self as the first binding we can then lookup resources in our converter. The converter needs to implement IMultiValueConverter (rather than IValueConverter) and can look something like this:
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(); } }
It's not something I do very often, but that should work from memory :)
It seems that you need to use DataTrigger class. It allows you to apply different styles to your button based on it's content.
For example following style will change button's background property to red based on value of data context object's property
<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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With