Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UWP transparent LinearGradientBrush

I'm having trouble with my c# UWP App.

<Grid VerticalAlignment="Bottom" Height="40" Grid.Row="3" Margin="0,0,0,-1">
  <Grid.Background>
    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
        <GradientStop Color="#00000000" Offset="0"/>
        <GradientStop Color="{StaticResource stdBackgroundColor}" Offset="1"/>
    </LinearGradientBrush>
  </Grid.Background>
</Grid>

This code snippet should show a transparent overlay at the bottom of the page, but instead it creates a blackish overlay, like it is adding transparent values on top of the existing background (which is also of Color stdBackgroundColor) and therefore looks quite strange (see image below)

Overlay problem

How can I achieve an transparent overlay to content (such as ScrollViewer) without this effect?

like image 266
user3079834 Avatar asked Oct 19 '25 21:10

user3079834


1 Answers

Disclaimer, I'm at work and I don't have access to a platform I can test this code in, but from what I've looked up it should work.

The underlying problem is one of color blending, namely that we want to smoothly blend from full alpha to any arbitrary color. The problem with starting with Color.Transparent is that you'll get a band of white while the alpha channel progresses more than the other components. A similar problem occurs with #00000000 as that has a band of black. The solution is to start with a version of your color that has the opacity set to 0. How we go about this is slightly different based on which version of XAML based application you are developing--and I find it difficult to keep them straight. In UWP we don't have an opacity mask and we can't create a gradient on opacity alone. The only thing left is to use an IValueConverter.

The Color property in GradientStop is a Color and not a Brush, as that would overly complicate the rendering system. So the first step we need is an IValueConverter that takes any Color and strips out the alpha value:

public class TransparentColorConverter : IValueConverter
{
    public object Convert(object value, Type targetType,
                          object parameter, string language)
    {
        Color convert = (Color) value; // Color is a struct, so we cast
        return Color.FromArgb(0, convert.R, convert.G, convert.B);
    }

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

The next challenge is to create a binding that we can use this color against. The binding object allows us to specify a Source, which can be any object we pass in. ElementName won't work because resources are referenced by key, not name.

<LinearGradientBrush x:Key="OpacityGradientBrush" StartPoint="0,0" EndPoint="0,1">
  <GradientStop Color="{Binding Source={StaticResource stdBackgroundColor},
                       Converter={StaticResource TransparentColorConverter}}" Offset="0"/>
  <GradientStop Color="{StaticResource stdBackgroundColor}" Offset="1"/>
</LinearGradientBrush>

Of course, don't forget to put the TransparentColorConverter in your Resources so you can reference it here. Personally, I would prefer not to have to use converters, but in this case I think it is warranted.

NOTE: We use Source in the binding so we can reference a static resource. If we had a property we could bind to, we could use a Path instead.


The answer below is valid for WPF, but not UWP. I wish Microsoft would stop redefining the same concept in incompatible ways, but this is the world we live in.

Correcting my answer based on this answer

You want to change your LinearGradientBrush to use the Opacity property rather than the color #00000000. The problem is that it is interpolating from basically black to your desired color. To get the affect you want you'll need to set up an opacity mask brush like this:

<LinearGradientBrush x:Key="OpacityGradientBrush" StartPoint="0,0" EndPoint="0,1">
  <GradientStop Color="#00FFFFFF" Offset="0"/>
  <GradientStop Color="#FFFFFFFF" Offset="1"/>
</LinearGradientBrush>

Then in the code you need to apply the opacity mask to, you reference it like this:

<Grid VerticalAlignment="Bottom" Height="40" Grid.Row="3"
    Background="{StaticResource stdBackgroundColor}"
    OpacityMask="{StaticResource OpacityGradientBrush} Margin="0,0,0,-1"/>

The problem is that if you want the blend to only affect the opacity, the rest of the color has to be the same. You'll get a band of your starting color fading in and changing to the ending color otherwise.

like image 181
Berin Loritsch Avatar answered Oct 22 '25 12:10

Berin Loritsch



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!