2

I'm wondering how to bind a color property of an element to the ViewModel without leaking the view implementation (e.g. WPF) into the ViewModel and thus creating a dependency. For example, I have a TextBlock and I've bound its Foreground property like this:

<TextBlock Name="MyTextBlock" Foreground="{Binding Path=PropName}" />

Many sources like this, this, this, etc. use System.Windows.Media.Brush from within the ViewModel, like this:

public System.Windows.Media.Brush PropName
{
    get
    {
        //assume presentation logic to determine correct color.
        return System.Windows.Media.Brushes.Red;
    }
}

I don't want my ViewModel to be tied to WPF (i.e. via System.Windows.Media.Brush) or any other presentation framework. Is there some way of doing it so that I can use a general or universal color type or even an RGB value and have it interpreted correctly in the XAML from the binding?

Community
  • 1
  • 1
rory.ap
  • 34,009
  • 10
  • 83
  • 174
  • To make sure I'm understanding you correctly, is this just an over complicated way of asking how to place a brush/color as a resource for a view without code behind and just xaml? – Chris W. Jun 02 '15 at 16:00
  • No, I'm really new to WPF. Can you elaborate on that? – rory.ap Jun 02 '15 at 16:02
  • 1
    1) You don't. 2) They're being cheap, which is fine. This isn't a dogma, it's a pattern. Side note--Why does your VM know or care about colors? It honestly shouldn't. But parts of your system may be represented by a certain color depending on the state it is currently in. Use converters to interpret the state of your VMs or your models and convert that state to a color. For example, if your Person model is invalid, convert that to Red. If it is valid, modified but unsaved, convert that to yellow. –  Jun 02 '15 at 17:22
  • You can simply return a string from your view model. The implicit TypeConverter will convert it to a Brush. You need to return a know color "Red" or return a valid #FFFFF color. – Postlagerkarte Jun 02 '15 at 17:40
  • Would you kindly map someone's answer or provide us more information? – Jon Koivula Jun 08 '15 at 14:07

4 Answers4

6

I would create an enumeration of colors. e.g:

enum Colors {Red, Green, Yellow, Pink, Blue};

Then if you are developing with WPF, you could just create a ValueConverter, where you determine if enumeration is Red you can convert it the way you want it and return it for control. That way you can separate the UI logic with viewmodel. Viewmodel tells what color and UI handles the rest.

If you want custom colors, upper answer is a good way of handling it.

Jon Koivula
  • 899
  • 1
  • 11
  • 24
1

Just Bind string with the Hex into Background property of the element like this(Course you'll need a Notify implementation)

XAML

<Border Background="{Binding anycolor}" />

Code

public string anycolor { get; set; }
Marco BFV
  • 100
  • 2
  • 14
0

If you don't want to reference those namespaces maybe you can return a string and use a converter containing something like :

var color = (Color)ColorConverter.ConvertFromString("Red");

or RGB

var color = (SolidColorBrush)(new BrushConverter().ConvertFrom("#ffaacc"));

I might not understand the question very well though.

Olaru Mircea
  • 2,570
  • 26
  • 49
  • I'm assuming your code examples would go in the code-behind. How would you accomplish that in XAML instead? – rory.ap Jun 02 '15 at 16:26
  • AFAIK can't be done without code. But does not need code behind. just need a separate independent and reusable converter class. Which is fine and perfectly good mvvm. – Baldrick Jun 02 '15 at 16:31
0

This is my new favorite creation (sorry about the VB):

Imports System.Windows.Data

Public Class MappingConverter
    Implements IValueConverter

    Public Property Mappings As New List(Of Mapping)


    Public Function Convert(value As Object, targetType As Type, parameter As Object, culture As Globalization.CultureInfo) As Object Implements IValueConverter.Convert
        Return Mappings.Where(Function(m) m.Source = value.ToString).FirstOrDefault
    End Function

    Public Function ConvertBack(value As Object, targetType As Type, parameter As Object, culture As Globalization.CultureInfo) As Object Implements IValueConverter.ConvertBack
        Throw New NotImplementedException
    End Function
End Class

Public Class Mapping
    Public Property Source As String
    Public Property Target As Object
End Class

And used like this:

 <UserControl.Resources>
        <wpflib:MappingConverter x:Key="SelectionHighlightConverter">
            <wpflib:MappingConverter.Mappings>
                <wpflib:Mapping Source="True" Target="{x:Static Brushes.CornflowerBlue}" />
                <wpflib:Mapping Source="False" Target="{x:Static Brushes.White}" />
            </wpflib:MappingConverter.Mappings>
        </wpflib:MappingConverter>
    </UserControl.Resources>

When you use that converter on a binding of a boolean property, the True or False will converted to the specified color. It can actually map any string convertable value (int, string, boolean, etc) to any object you want.

Bradley Uffner
  • 16,641
  • 3
  • 39
  • 76