5

I stucked with "simple" converting. I have a method. It checks connection. If connection established it change boolean property of my viewmodel. What I want to do, is to display colored string on my form (red-colored "Connection failed" or green-colored "Connection established" depending on boolean property) but i don't have any idea how to do it.

Taterhead
  • 5,763
  • 4
  • 31
  • 40
dantey89
  • 2,167
  • 24
  • 37
  • 1
    I think this could be achieved by just a data trigger. But you don't have to post a question for this, you can easily found out this type of question on this community. – Kylo Ren Feb 11 '16 at 10:24

6 Answers6

9

Use below(change control type with what you are using):

<TextBox Text="content" >
    <TextBox.Style>
        <Style TargetType="TextBox">
            <Style.Triggers>
                <DataTrigger Binding="{Binding ConnectionStatus}" Value="true">
                    <Setter Property="Background" Value="Red"></Setter>
                </DataTrigger>
                <DataTrigger Binding="{Binding ConnectionStatus}" Value="false">
                    <Setter Property="Background" Value="Green"></Setter>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </TextBox.Style>
</TextBox>
Kylo Ren
  • 8,551
  • 6
  • 41
  • 66
  • 1
    Even better than my `IValueConvertor` proposal :-) – Stefan Feb 11 '16 at 10:21
  • 1
    I am curious why this is down voted. I think the design where only the UI is involved is better than the IValueConvertor option. – Stefan Feb 11 '16 at 10:24
  • @Stefan yeah, me too, It's second time this day. check this out http://stackoverflow.com/questions/35328324/create-a-dependencypropery-with-observable-collection-in-viewmodel here i was voted -2 before a moderator intervened – Kylo Ren Feb 11 '16 at 10:26
  • anyone down voting please have the courtesy to add a comment too – Kylo Ren Feb 11 '16 at 10:27
  • 2
    Upvoted because the simple state change can better be represented using Triggers. The downvotes would probably be out of fear the xaml gets to much logic and cluttered. This is always problematic but not the case at this point. – Nicholas Schuster Feb 11 '16 at 10:28
  • 2
    @KyloRen, why do you use 2 DataTriggers? `` in ` – ASh Feb 11 '16 at 10:32
  • 2
    @ASh cause i was not sure if user want that element with a default color or not. :) else i would have given a default color in Background property and 1 data trigger would be enough – Kylo Ren Feb 11 '16 at 10:33
7

You have two options here, for both of which I will simply provide some resources as you did not provide any specific code:

The first option is to update the property of the text using a trigger. This would be implemented in xaml and simply watched the bound property to take a specific value (in you case true or false) and updates the color accordingly. This is also what @Kylo-Ren did. Information about this can for example be found here:

http://www.wpf-tutorial.com/styles/trigger-datatrigger-event-trigger/

The other option is to use the IValueConverter interface and convert the boolean to a color. This is what @Stefan did. More info here:

http://www.codeproject.com/Tips/868163/IValueConverter-Example-and-Usage-in-WPF

I would recommend the first version if you only have a very limited range of values that the property can take and/or you want to update multiple visual properties at once.

The second version works better for more complex conversions (like converting a complete object to a formatted string) but can not be easily used to update multiple visual properties.

Rule of thumb:

I want to indicate a state => use Trigger

I want to display an objects value in a specific way (e.g. Text) => use IValueConverter

2

The best way is to use IValueConverter for binding. Just implement new class of converter:

public class BoolToColorConverter : IValueConverter
{
    object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var val = (bool) value;
        // your convertion logic here
        // return Brushes.Black;
    }

    object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}

Next, add your converter to the resources in XAML:

<Window.Resources>
    <l:BoolToColorConverter x:Key="boolToColorConverter" />
</Window.Resources>

And use it in data binding:

<TextBox Background="{Binding YourBoolPropertyName, 
        Converter={StaticResource boolToColorConverter}}" />

You can read more about converters here.

Vadim Martynov
  • 8,602
  • 5
  • 31
  • 43
2

Although a Converter was already posted I have created a BooleanToColorConverter which is more reusable. You can use it for different scenarios as shown below.

[ValueConversion(typeof(bool), typeof(SolidColorBrush))]
public class BooleanToColorConverter : IValueConverter
{
    public Brush TrueBrush { get; set; }

    public Brush FalseBrush { get; set; }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var boolValue = value as bool? ?? true;
        if (parameter != null && parameter.ToString() == "!")
        {
            boolValue = !boolValue;
        }

        if (boolValue)
        {
            return TrueBrush;
        }
        return FalseBrush;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Now in XAML in the Resource you can have something like this:

<ResourceDictionary>
    <converter:BooleanToColorConverter x:Key="BooleanToColorConverter" FalseBrush="#4CFF0000" TrueBrush="#4C00FF00" />
    <converter:BooleanToColorConverter x:Key="ReadOnlyToColorConverter" TrueBrush="LightGray"/>
</ResourceDictionary>

And now you can use it on the Background attribute like this (IsReadOnly is a property of Type bool):

Background="{Binding IsReadOnly, Converter={StaticResource ReadOnlyToColorConverter}}"

ps. this piece of code:

if (parameter != null && parameter.ToString() == "!")
    {
        boolValue = !boolValue;
    }

is just so you can invert easy your color if you need it. You can use it like this:

Background="{Binding IsReadOnly, Converter={StaticResource ReadOnlyToColorConverter}, ConverterParameter=!}"
Devid
  • 1,823
  • 4
  • 29
  • 48
1
  1. Create a IValueConverter, which converts boolean value to Color if parameter is "Color" and bool to Text if parameter is "Text".
  2. Imagine you have a TextBlock on the form, where you want to show text(it can be any control you like):

<TextBlock Text="{Binding MyBoolValue,Converter={StaticResource MyConverter,ConverterParameter=Text}}" Foreground="{Binding MyBoolValue,Converter={StaticResource MyConverter,ConverterParameter=Color}}"/>.

Solution above is incomplete and shows only basics. Feel free to ask additional questions in case you have difficulties.

-1

You can either create SolidColorBrush property named for example ConnectionStatusColor. In its get you can do something like:

return connectionSuccess ? Brushes.Green : Brushes.Red

Don't forget to implement INotifyPropertyChanged so the binding gets applied.

Or you can create IValueConverter and use it in your binding.

 class BoolToBrushConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (bool) value ? Brushes.Green : Brushes.Red;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
Filip
  • 1,824
  • 4
  • 18
  • 37