14

How do I programmatically change the color of an ellipse that is defined in XAML based on a variable?

Everything I've read on binding is based on collections and lists -can't I set it simply (and literally) based on the value of a string variable? string color = "red" color = "#FF0000"

ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
user294382
  • 1,709
  • 3
  • 10
  • 8

4 Answers4

24

It's worth pointing out that the converter the other posts reference already exists, which is why you can do <Ellipse Fill="red"> in xaml in the first place. The converter is System.Windows.Media.BrushConverter:

        BrushConverter bc = new BrushConverter();
        Brush brush = (Brush) bc.ConvertFrom("Red");

The more efficient way is to use the full syntax:

myEllipse.Fill = new SolidColorBrush(Colors.Red);

EDIT in response to -1 and comments:

The code above works perfectly fine in code, which is what the original question was asking about. You also don't want an IValueConverter - these are typically used for binding scenarios. A TypeConverter is the right solution here (because you're one-way converting a string to a brush). See this article for details.

Further edit (having reread Aviad's comment): you don't need to explicitly use the TypeConverter in Xaml - it's used for you. If I write this in Xaml:

<Ellipse Fill="red">

... then the runtime automagically uses a BrushConverter to turn the string literal into a brush. That Xaml is essentially converted into the equivalent longhand:

<Ellipse>
  <Ellipse.Fill>
     <SolidColorBrush Color="#FFFF0000" />
  </Ellipse.Fill>             
</Ellipse>

So you're right - you can't use it in Xaml - but you don't need to.

Even if you had a string value that you wanted to bind in as the fill, you don't need to specify the converter manually. This test from Kaxaml:

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:s="clr-namespace:System;assembly=mscorlib">
  <Page.Resources>
    <s:String x:Key="col">Red</s:String>
  </Page.Resources>

  <StackPanel>  
    <Ellipse Width="20" Height="20" Fill="{Binding Source={StaticResource col}}" />
  </StackPanel>
</Page>

Strangely, you can't just use the StaticResource col and still have this work - but with the binding it and automatically uses the ValueConverter to turn the string into a brush.

Dan Puzey
  • 33,626
  • 4
  • 73
  • 96
  • This does not answer the question, the `BrushConverter` does not implement `IValueConverter` so you cannot use it in XAML. – Aviad P. Mar 17 '10 at 08:59
  • 1
    Edited my answer rather than replying here because I think it's worth pointing out why I'm right in detail... – Dan Puzey Mar 17 '10 at 10:07
7

what you will need to do is implement a custom converter to convert the colour to the brush object. Something like this...

public class ColorToBrushConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        System.Drawing.Color col = (System.Drawing.Color)value;
        Color c = Color.FromArgb(col.A, col.R, col.G, col.B);
        return new System.Windows.Media.SolidColorBrush(c);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        SolidColorBrush c = (SolidColorBrush)value;
        System.Drawing.Color col = System.Drawing.Color.FromArgb(c.Color.A, c.Color.R, c.Color.G, c.Color.B);
        return col;
    }
}

And then specify that converter in your binding

Fill="{Binding Colors.Red, Converter={StaticResource ColorToBrushConverter }"
Miquella
  • 1,074
  • 2
  • 13
  • 25
Leigh S
  • 1,837
  • 11
  • 17
  • This would be correct if you'd convert to a `Brush` object instead of a `Color` object. Simply using a `BrushConverter` instead of a `ColorConverter` should do the trick. Although I think you need an instance of that converter, the `ConvertFromString` method is not static, is it? – Aviad P. Mar 16 '10 at 00:17
  • If you bind using a color then you are free to use the Colors class which has intellisense on the color names as well. – Leigh S Mar 16 '10 at 23:18
2

use

System.Windows.Media

If the name of your ellipse in your XAML is my_ellipse,
write something like this:

my_ellipse.Fill = System.Windows.Media.Brushes.Red;

or this:

my_ellipse.Fill = (SolidColorBrush)new BrushConverter().ConvertFromString("#F4F4F5")
Hille
  • 2,123
  • 22
  • 39
Alex Stoliar
  • 305
  • 3
  • 8
0

A quick work around for this (Although its not binding, and less efficient) is to check the status of an object/element and update the new/other object(s) based on the status, I'll provide a Basic Example Below.

You can do this in MVVM by getting the status of MainWindow Objects from a User Control and changing whatever you want from the MainWindow object status.

Note: this will not work for 2 themed applications and other scenarios where more than basic use case is needed. (Example: Dark Mode, Etc)

In my example, I am using data to draw a "text" on screen (FrontFog_Text, Which is why the text is using the .Fill Property in my case).

I am not using this in my application but came across this when testing a few things so I thought I would share in this thread while I search for my answer!

 private void FrontFog_ToggleButton_Unchecked(object sender, RoutedEventArgs e)
    {
        if (((MainWindow)App.Current.MainWindow).Theme_Control.IsChecked == true)
        {
            FrontFog_Text.Fill = new SolidColorBrush(System.Windows.Media.Colors.White);
        }
        else if (((MainWindow)App.Current.MainWindow).Theme_Control.IsChecked == false)
        {
            FrontFog_Text.Fill = new SolidColorBrush(System.Windows.Media.Colors.Black);
        }
    }
Sam
  • 1