Question

I've created a custom control that displays a color spectrum. I'm overriding the OnRender() method to draw the control with the colors. For some reason the colors that are "calculated" (the R G B values) have some transparency, even though I'm setting the Alpha value (A) in the max possible value (255). I've created a test window that shows some text on the background and, my control and a Border with a LinearGradient background and the text can be seen behind my control but not behind the Border, which clearly shows that my control has some transparency set. Any ideas why my calculated colors have transparency even though I'm setting A=255? I appreciate any suggestions. Thanks!

Here's my Window.xaml and my control's .cs:

MainWindow.xaml

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:Views="clr-namespace:ColorBarTest.Views"
        x:Class="ColorBarTest.MainWindow"
        Title="MainWindow" Height="671.622" Width="720.102">

    <Grid>
        <TextBlock Margin="0,66,0,558" HorizontalAlignment="Left" Width="218"><Run Text="TESTING THE OPACITY O"/><Run Text="F C"/><Run Text="OLOR BAR"/></TextBlock>
        <Views:TestRender Margin="0,65,671,0" />
        <Border Margin="100,65,671,0"/>
        <Border BorderBrush="Black" BorderThickness="1" HorizontalAlignment="Left" Height="577" Margin="105,65,0,0" VerticalAlignment="Top" Width="42">
            <Border.Background>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="Red" Offset="1"/>
                    <GradientStop Color="Magenta"/>
                </LinearGradientBrush>
            </Border.Background>
        </Border>
    </Grid>
</Window>

TestRender.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace ColorBarTest.Views
{
    public class TestRender : Control
    {
        private int Max = 99;
        private int Min = 1;

        private Color StartColor = Colors.Red;

        private Color EndColor = Colors.Fuchsia;

        static TestRender()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(TestRender), new FrameworkPropertyMetadata(typeof(TestRender)));
        }

        protected override void OnRender(DrawingContext drawingContext)
        {

            for (double pixel = 0; pixel < ActualHeight; pixel++)
            {
                var value = ConvertYPixelToColorHandleValue(pixel);
                var color = CalculateRGBA(value);
                var brush = new SolidColorBrush(color);
                brush.Opacity = 1.0f;
                var pen = new Pen(brush, 1.0f);
                drawingContext.DrawLine(pen, new Point(0, pixel), new Point(ActualWidth, pixel));
                //Console.WriteLine("Value: {0}", value);
            }
            var pen2 = new Pen(new SolidColorBrush(Colors.Red), 5.0d);
            var pen3 = new Pen(new SolidColorBrush(Colors.Fuchsia), 5.0d);
            drawingContext.DrawLine(pen3, new Point(0, 0), new Point(ActualWidth, 0));
            drawingContext.DrawLine(pen2, new Point(0, ActualHeight), new Point(ActualWidth, ActualHeight));

        }

        private float ConvertYPixelToColorHandleValue(double tickDrawY)
        {
            var pixelPercent = ((tickDrawY) / (float)ActualHeight);

            return (Max - (float)(pixelPercent * (Max - Min)));
        }


        public Color CalculateRGBA(double value)
        {
            var rate = (float)((value - Min) / (Max - Min));
            float posRate = rate - 1;
            // Interpolate the color, there will be a HSV interpolation also
            return RgbLinearInterpolate(posRate);
        }

        public Color RgbLinearInterpolate(double rate)
        {
            var nr = 1.0 - rate;
            var r = (byte)((nr * StartColor.R) + (rate * EndColor.R));
            var g = (byte)((nr * StartColor.G) + (rate * EndColor.G));
            var b = (byte)((nr * StartColor.B) + (rate * EndColor.B));

            return new Color { R = r, G = g, B = b, A = 255 };
        }
    }
}

This is how it looks:

Color Bar Test screenshot

Was it helpful?

Solution

At the top of your OnRender, add this:

this.SetValue(RenderOptions.EdgeModeProperty, EdgeMode.Aliased);

Or, change your xaml to this:

<Views:TestRender Margin="0,65,671,0" RenderOptions.EdgeMode="Aliased" />

Or, you could try drawing overlapping rectangles:

//drawingContext.DrawLine(pen, new Point(0, pixel), new Point(ActualWidth, pixel));
drawingContext.DrawRectangle(brush, pen, new Rect(new Point(0, pixel - 0.25), new Point(ActualWidth, pixel + 0.25)));
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top