Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make an element look like it's "below" the border, but "above" the border's content, when the border has rounded corners?

Tags:

c#

wpf

xaml

TL/DR:

How to make an element look like it's "below" the border, but "above" the border's content, when the border has rounded corners?

Elaboration:

This is what I'm trying to accomplish: when the mouse moves into the border, a "curtain" is drawn from the top-left corner until it covers either the whole border's content or maybe just 3/4 of it, like this example:

enter image description here

This "curtain" is intended to carry additional controls to update its box content.

I'm stuck right now creating the red path - I can't make it perfectly aligned along the black border, so it'll look like it comes from below the border, but above its content.

Here is the XAML I currently have:

<UserControl x:Class="FamilyTree.GroupBox"
             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="100" d:DesignWidth="100">
    <Grid>
        <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
            <StackPanel.Resources>
                <Style TargetType="{x:Type TextBlock}">
                    <Style.Setters>
                        <Setter Property="VerticalAlignment" Value="Center" />
                    </Style.Setters>
                </Style>
            </StackPanel.Resources>

            <Border CornerRadius="5" BorderBrush="Black" BorderThickness="1" VerticalAlignment="Center" ToolTip="{Binding ToolTipString}" Background="White">
                <Grid>
                    <StackPanel Margin="3">
                        <StackPanel.Resources>
                            <Style TargetType="{x:Type Border}">
                                <Setter Property="CornerRadius" Value="3" />
                                <Setter Property="BorderBrush" Value="Blue" />
                                <Setter Property="BorderThickness" Value="0.6" />
                                <Setter Property="VerticalAlignment" Value="Center" />
                                <Setter Property="Padding">
                                    <Setter.Value>
                                        <Thickness Right="2" />
                                    </Setter.Value>
                                </Setter>
                                <Setter Property="Margin" Value="0" />
                            </Style>
                        </StackPanel.Resources>
                        <StackPanel Orientation="Horizontal">
                            <Border>
                                <TextBlock Text="Name" />
                            </Border>
                            <TextBlock Text="/"/>
                            <Border>
                                <TextBlock Text="Family" />
                            </Border>
                        </StackPanel>
                        <TextBlock Text="Group"/>
                    </StackPanel>
                    <Path Stroke="Red" Fill="Red" Data="M50,0 L5,0 C1.5,0 0,1.5 0,5 L0,50" StrokeLineJoin="Round" Margin="0.5"/>
                </Grid>
            </Border>
        </StackPanel>
    </Grid>
</UserControl>
like image 950
Tar Avatar asked Mar 26 '15 13:03

Tar


1 Answers

If it were me. I would use a LinearGradient animation to fill your Border without using another object like a Path to accomplish this effect. So as just a quick and sloppy example. Something like this;

Our Storyboard to control the StartPoint/EndPoint of the Gradient to bring it in from an angle;

<Storyboard x:Key="Curtain">
   <DoubleAnimationUsingKeyFrames 
                       Storyboard.TargetProperty="(Panel.Background).(GradientBrush.GradientStops)[1].(GradientStop.Offset)"                                                                          
                       Storyboard.TargetName="border">
      <EasingDoubleKeyFrame KeyTime="0:0:1" Value="1"/>
    </DoubleAnimationUsingKeyFrames>
    <DoubleAnimationUsingKeyFrames 
                       Storyboard.TargetProperty="(Panel.Background).(GradientBrush.GradientStops)[0].(GradientStop.Offset)"                                                                          
                       Storyboard.TargetName="border">
       <EasingDoubleKeyFrame KeyTime="0:0:1" Value="1"/>
     </DoubleAnimationUsingKeyFrames>
</Storyboard>

Then our Border;

<Border x:Name="border" BorderBrush="Blue" BorderThickness="1" Height="200" Width="350">
   <Border.Background>
      <LinearGradientBrush EndPoint="0.964,0.992" StartPoint="0.017,0.019">
         <GradientStop Color="#FFF90202" Offset="0"/>
         <GradientStop Offset="0.001"/>
      </LinearGradientBrush>
   </Border.Background>             
</Border>

This way, it won't matter if your CornerRadius is set, or if you wanted to get fancy, you could do the same on any shape or Path no matter of it's Geometry and it will spread the area evenly while it performs the animation. However the Border would need a higher z-index or lower placement in the DOM to render over the top of the content.

You'll probably want to tweak the values on your StartPoint/EndPoint and KeyTime to get exactly what you want, but this was just a quick 60sec example to convey the concept.

Hope this helps, cheers!

like image 198
Chris W. Avatar answered Oct 22 '22 06:10

Chris W.