lose_the_grimm
lose_the_grimm

Reputation: 413

Change the color of an ellipse based off a boolean

<Grid Grid.Row="1" Width="500" Height="500">
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <Ellipse Fill="Red" HorizontalAlignment="Center" Height="25" Margin="0,0,0,0" Stroke="Black" VerticalAlignment="Center" Width="25"/>
    <Ellipse Fill="Red" HorizontalAlignment="Center" Height="25" Margin="0,0,0,0" Stroke="Black" VerticalAlignment="Center" Width="25" Grid.Row="1"/>
    <Ellipse Fill="Red" HorizontalAlignment="Center" Height="25" Margin="0,0,0,0" Stroke="Black" VerticalAlignment="Center" Width="25" Grid.Row="3"/>
    <Ellipse Fill="Red" HorizontalAlignment="Center" Height="25" Margin="0,0,0,0" Stroke="Black" VerticalAlignment="Center" Width="25" Grid.Column="4"/>
    <Ellipse Fill="Red" HorizontalAlignment="Center" Height="25" Margin="0,0,0,0" Stroke="Black" VerticalAlignment="Center" Width="25" Grid.Column="4" Grid.Row="4"/>
</Grid>

Given the above XAML I want the dots to be green when a property is true. I'm assuming I'd do it with a DataTrigger, but the only way I can think of doing it involved duplicating it for each ellipse. It seems hackish to me and was wondering if their is a better solution. Each ellipse is based of a single property, but again that seems like a lot of duplicate code. Ideally what I want is this view to reflect the state of a list of "Stations" using a boolean to determine if they're available or not. The state of each is one-way and won't change while the view is up.

I'm far to new at WPF and XAML to come up with an elegant solution. I cringe every time I attempt something as it just seems like a complete hack.

EDIT: Thanks to @Alastair's answer I've gotten it working.

Upvotes: 2

Views: 9657

Answers (2)

Brandorf
Brandorf

Reputation: 816

Another approach is to bind the fill to your Boolean value directly and use a converter to change the style as you want.

Your converter might look something like this:

    class StatusToColor : IValueConverter
    {
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                SolidColorBrush retColor = new SolidColorBrush();
                retColor.Color = System.Windows.Media.Color.FromRgb(0, 0, 0);
                if ((bool)value)
                {
                     retColor.Color = System.Windows.Media.Color.FromRgb(255, 0, 0);
                }
                else
                {
                     retColor.Color = System.Windows.Media.Color.FromRgb(0, 128, 0);
                }
                return retColor;
            }

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

You can then define the converter in your xaml resources:

<Window>    
    <Window.Resources>
        <c:StatusToColor x:Key="MyConverter"/>
    </Window.Resources>
...

And set up your bindings as such:

<Ellipse Fill="{Binding SomeProperty, Converter={StaticResource MyConverter}}" HorizontalAlignment="Center" Height="25" Margin="0,0,0,0" Stroke="Black" VerticalAlignment="Center" Width="25"/>

Upvotes: 5

Alastair Pitts
Alastair Pitts

Reputation: 19601

So I would make a custom UserControl that contains an Ellipse.

You can then put a the datatrigger into the UserControl. You then bind the DataContext of the custom control to your boolean property, then bind the DataTrigger to the DataContext of your UserControl.

Thus you are able to keep your XAML clean.

EDIT:

A basic user control. THis should be defined in a separate file, as opposed to a resource. Just right-click the project -> Add -> New Item... then choose WPF UserControl.

<UserControl x:Class="Test_WPF.MyEllipseControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <Ellipse  HorizontalAlignment="Center"
                  Height="25"
                  Margin="0,0,0,0"
                  Stroke="Black"
                  VerticalAlignment="Center"
                  Width="25" 
                  Fill="Red">
            <Ellipse.Style>
                <Style TargetType="Ellipse">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding Path=IsAvailable}"
                                     Value="True">
                            <Setter Property="Fill"
                                    Value="Green" />
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </Ellipse.Style>
        </Ellipse>
    </Grid>
</UserControl>

and then you'd use it:

<local:MyEllipseControl DataContext="{Binding Path=Station1}" />

where the local namespace is just your local projects namespace.

Upvotes: 10

Related Questions