Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic Style Binding with IValueConverter

I am trying to set a style, which is defined in the App.xaml, dynamically when loading a user control and it's just not applying the style for some reason (i.e. there is no error occurring, it's just not applying the style).

I'm sure it's because I've defined the binding wrong, but I'm unable to figure out what I need to do differently to get it to work.

App.xaml Style

The style I'm after is the RunningTitleBlock and it's comprised of a couple other styles that I've included in the below code sample.

<Style TargetType="Label">
    <Setter Property="Margin" Value="4"/>
</Style>

<Style TargetType="Label"
       BasedOn="{StaticResource {x:Type Label}}"
       x:Key="HeaderBlock">
    <Setter Property="FontSize" Value="16"/>
    <Setter Property="FontWeight" Value="Bold"/>
    <Setter Property="Foreground" Value="White"/>
</Style>

<Style TargetType="Label"
       BasedOn="{StaticResource ResourceKey=HeaderBlock}"
       x:Key="TitleBlock">
    <Setter Property="Foreground" Value="Black"/>
</Style>

<Style TargetType="Label"
       BasedOn="{StaticResource ResourceKey=TitleBlock}"
       x:Key="RunningTitleBlock">
    <Setter Property="Background">
        <Setter.Value>
            <LinearGradientBrush StartPoint="0.0, 0.5"
                                 EndPoint="1.0, 0.5">
                <GradientStop Color="White" Offset="0.0"/>
                <GradientStop Color="Green" Offset="1.0"/>
            </LinearGradientBrush>
        </Setter.Value>
    </Setter>
</Style>

Binding on the user control

I'm trying to get the Binding to bind to a value returned from a value converter.

Style="{DynamicResource ResourceKey={Binding Path=MonitoringType, Converter={StaticResource TSConverter}}}"

Code

MonitoringTypes Enum

public enum MonitoringTypes
{
    Running,
    Failed,
    Paused,
    Favorites,
}

User Control

Here what I'm trying to do is concatenate the string value of the MonitoringTypes enum value that's passed in with some well known text to build a style name that exists in the App.xaml. The value converter is being called and returning the correct value, but for some reason the style isn't applying.

/// <summary>
/// Interaction logic for MonitorWorkflow.xaml
/// </summary>
public partial class MonitorWorkflow : UserControl
{
    public MonitorWorkflow(MonitoringTypes monitoringType)
    {
        InitializeComponent();

        this.DataContext = new MonitorWorkflowViewModel { MonitoringType = monitoringType };
    }
}

public class MonitorWorkflowViewModel
{
    public MonitoringTypes MonitoringType { get; set; }
}

public class TitleStyleValueConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var type = (MonitoringTypes)value;
        return string.Format("{0}TitleBlock", Enum.GetName(typeof(MonitoringTypes), type));
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return Enum.Parse(typeof(MonitoringTypes), value.ToString().Substring(0, value.ToString().IndexOf("TitleBlock")));
    }
}
like image 507
Mike Perrenoud Avatar asked Aug 21 '12 18:08

Mike Perrenoud


1 Answers

My suggestion would be to skip the DynamicResource statement and using the Converter provide the Style directly.

Style="{Binding Path=MonitoringType, Converter={StaticResource TSConverter}}"

In TSConverter, you can return a Style rather than a string. Kind of like this:

public class TitleStyleValueConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, 
        System.Globalization.CultureInfo culture)
    {
        var type = (MonitoringTypes)value;
        var styleToReturn = FindResource(
            string.Format("{0}TitleBlock", 
                Enum.GetName(typeof(MonitoringTypes), type)));
        if (styleToReturn != null)
            return (Style)styleToReturn;
        else 
            return null;
    }

    public object ConvertBack(object value, Type targetType, object parameter,
        System.Globalization.CultureInfo culture)
    {
        // not sure if you need this anymore... 
        return Enum.Parse(typeof(MonitoringTypes), value.ToString().Substring(0,
           value.ToString().IndexOf("TitleBlock")));
    }
}

This is what I did but with the following code instead. I actually just answered my own question while you answered it as well. Good timing!

public class TitleStyleValueConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var type = (MonitoringTypes)value;
        return App.Current.Resources[string.Format("{0}TitleBlock", Enum.GetName(typeof(MonitoringTypes), type))];
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return Enum.Parse(typeof(MonitoringTypes), value.ToString().Substring(0, value.ToString().IndexOf("TitleBlock")));
    }
}
like image 56
code4life Avatar answered Sep 26 '22 10:09

code4life