DropShadowPanel and border corner radius - c#

I want to make drop shadow effect with border control. I am using UWP toolkit.
<controls:DropShadowPanel x:Name="dspShadow"
BlurRadius="10"
ShadowOpacity="0.8"
OffsetX="0"
OffsetY="0"
Color="Black">
<Border x:Name="borderMain" Background="Red" CornerRadius="10"/>
</controls:DropShadowPanel>
But it doesn't recognize corner radius, the result is like this:
And I need it to look like this:
Any ideas how to achieve this?

You need to mask it. Currently you can only get the mask from TextBlock, Shape and Image. In this case just replace the Border with a Rectangle.
<controls:DropShadowPanel x:Name="dspShadow"
BlurRadius="10"
OffsetX="0"
OffsetY="0"
ShadowOpacity="0.8"
Color="Black">
<Rectangle Width="100"
Height="48"
Fill="Red"
RadiusX="10"
RadiusY="10" />
</controls:DropShadowPanel>

Related

How to imitate OuterGlowBitmapEffect using WPF effects?

I tried using DropShadowEffect but it's "glow" strength weakens when you increase BlurRadius. I want to have strong outer glow like the image below.
If I stack the same effect a dozen times I am able to get this, but the performance tanks after this. Is this possible to do using WPF with a single effect?
Depending on how large you want the radius of the blur to be and how smooth the result needs to be, you could stack different effects like gradient stops instead of repeatedly stacking the same effect.
Like you pointed out, the DropShadowEffect strength gets weaker as the BlurRadius increases.
<TextBox Text="DropShadowEffect">
<TextBox.Effect>
<DropShadowEffect BlurRadius="50"
ShadowDepth="0"
Color="Blue"
Opacity="1"/>
</TextBox.Effect>
</TextBox>
Additionally, applying effects directly to the TextBox impacts the rendering quality of the text. The proposed solution to the linked question (setting TextOptions.TextFormattingMode="Display" on the Window) also has layout implications. Instead, you can draw a Rectangle with a BlurEffect behind your element.
<Rectangle Fill="Blue"
Height={Binding ElementName=MyTextBox, Path=ActualHeight}"
Width={Binding ElementName=MyTextBox, Path=ActualWidth}">
<Rectangle.Effect>
<BlurEffect Radius="50"/>
</Rectangle.Effect>
</Rectangle>
<TextBox x:Name="MyTextBox" Text="Rectangle with BlurEffect"/>
You can then add an additional Rectangle for each gradient stop. Here there are two: one at 50 to define the overall size of the blur, and one at 30 to strengthen the glow around the control.
<Rectangle Fill="Blue"
Height={Binding ElementName=MyTextBox, Path=ActualHeight}"
Width={Binding ElementName=MyTextBox, Path=ActualWidth}">
<Rectangle.Effect>
<BlurEffect Radius="50"/>
</Rectangle.Effect>
</Rectangle>
<Rectangle Fill="Blue"
Height={Binding ElementName=MyTextBox, Path=ActualHeight}"
Width={Binding ElementName=MyTextBox, Path=ActualWidth}">
<Rectangle.Effect>
<BlurEffect Radius="30"/>
</Rectangle.Effect>
</Rectangle>
<TextBox x:Name="MyTextBox" Text="Two Rectangles with BlurEffect"/>
You asked about the perceived sharpness around the corners of the TextBox and I must admit I don't have a good solution. I initially considered rounding the corners of the blurred elements behind your control by using a Border instead of a Rectangle, but I honestly don't see much of a difference.
<!-- Remove the CornerRadius property for square corners. -->
<Border CornerRadius="10" Background="Blue">
<Border.Effect>
<BlurEffect Radius="50"/>
</Border.Effect>
</Border>
<Border CornerRadius="10" Background="Blue">
<Border.Effect>
<BlurEffect Radius="30"/>
</Border.Effect>
</Border>
Of course, you could always make the background objects larger than your control. Here they are in the same cell of a Grid but there is extra space for the Border to grow because the TextBox has a Margin. A smaller top/bottom margin and larger left/right margin means the glow will be more uniform around the control.
<!-- These items should be in the same cell of a Grid -->
<Border CornerRadius="10" Background="Blue">
<Border.Effect>
<BlurEffect Radius="50"/>
</Border.Effect>
</Border>
<Border CornerRadius="10" Background="Blue">
<Border.Effect>
<BlurEffect Radius="30"/>
</Border.Effect>
</Border>
<TextBox Text="TextBox has an 8px, 4px margin" Margin="8 4"/>

Fit Border around arbitrary Path

I have a Path based on a group of rectangle/ellipse Geometry. When I put an auto-sized Border around it, the border shrinks to fit the RectangleGeometry but does something weird with the EllipseGeometry, as shown below. Anyone know how to fix it so the Border (shown in blue) fits snugly around the whole thing?
Ultimately, I want a Border or a Panel that fits an arbitrary, runtime-generated Path (including the stroke thickness), and I need the geometry size maintained.
Sample code:
<Border BorderBrush="Blue" BorderThickness="2"
HorizontalAlignment="Center" VerticalAlignment="Center">
<Path Stroke="Orange" StrokeThickness="5" Fill="Red">
<Path.Data>
<GeometryGroup>
<EllipseGeometry Center="-10,-10" RadiusX="12" RadiusY="12" />
<EllipseGeometry Center="70,0" RadiusX="70" RadiusY="10">
<EllipseGeometry.Transform>
<RotateTransform Angle="-25" CenterX="50" CenterY="0" />
</EllipseGeometry.Transform>
</EllipseGeometry>
<RectangleGeometry Rect="0,0,100,100" />
</GeometryGroup>
</Path.Data>
</Path>
</Border>
You may set the Path's Stretch property and bind its Width to the Width of the Bounds of the Geometry:
<Path ... Stretch="Uniform"
Width="{Binding Data.Bounds.Width, RelativeSource={RelativeSource Self}}">
...
</Path>
As the Geometries's Bounds do not contain the rendered Path's StrokeThickness, you may alternatively put the Border into a Canvas (which does not resize its child elements at all), and don't set the Path's Width. This may may however lead to problems when you want to center the Canvas in an outer Grid. It's actual size appears to be zero.
<Canvas>
<Border BorderBrush="Blue" BorderThickness="2">
<Path ... Stretch="Uniform">
...
</Path>
</Border>
</Canvas>

Resizable circle button xaml

I'm developping a universal app for Windows in XAML/C# and I can't manage to create a circle button that I can resize. I use an Ellipse with uniform stretch so as to make it circle and a ContentPresenter.
<ControlTemplate TargetType="Button">
<Grid>
<Ellipse Stretch="Uniform">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
The problem is a uniform ellipse is automatically aligned top, left, and it's impossible to make it stretch the grid. When I resize the button, the ContentPresenter stays in the center while the ellipse stays in the top left corner. I'd like to be able to resize the button and that the text stays in the center of the circle.
Thanks for help!
You may use a Path with a circular EllipseGeometry:
<ControlTemplate TargetType="Button">
<Grid>
<Path Stretch="Uniform" ...>
<Path.Data>
<EllipseGeometry RadiusX="1" RadiusY="1"/>
</Path.Data>
</Path>
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
You would however have to explicitly set the Width or Height of the Button, otherwise it would take up all available space.
I've also found another solution which is to use a ViewBox:
<ControlTemplate TargetType="Button">
<ViewBox>
<Grid>
<Ellipse Stretch="Uniform" Width="50" Height="50">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</ViewBox>
</ControlTemplate>
The ViewBox automatically scales everything when resized. You have to set Width and Height, but it's only to set proportions. Very useful when using the user control with both Windows and Windows Phone.
Thanks for your answers!

InkPresenter draw only in transparent area

I have an InkPresenter and this image with a transparent background. I want my strokes to be drawn only in the transparent area and ignore the black border of the shape. How is it possible?
here is an example using WPF, same applies to InkPresenter, you can use InkPresenter.Clip property to define the clip region
<Border BorderBrush="Green"
BorderThickness="1"
Width="200"
Height="200">
<Grid>
<InkCanvas>
<InkCanvas.Clip>
<EllipseGeometry RadiusX="98"
RadiusY="98"
Center="100,100" />
</InkCanvas.Clip>
</InkCanvas>
<Ellipse Stroke="Blue"
StrokeThickness="2" />
</Grid>
</Border>
result
I was able to solve my problem using Opacity Mask:
<InkPresenter.OpacityMask>
<ImageBrush ImageSource="{Binding ImageMask}" />
</InkPresenter.OpacityMask>

How does one increase the hit testing radius on a rectangle in WPF?

Let's say I have a rectangle like this:
<Rectangle Grid.Column="1"
Stroke="Red"
StrokeDashArray="4.0 4.0"
StrokeThickness="{Binding Path=CurrentThickness}"
Visibility="{Binding Path=VisibleRectangle,
Converter={StaticResource VisibilityConverter}}"
MouseUp="HandleMouseUp" />
This works for doing hit testing on the rectangle itself for the MouseUp event. However, the typical width of the rectangle is 1px wide, making clicking on the edge of the rectangle difficult. I would like to make the "effective click border size" for the Rectangle's stroke to be larger than the visual appearance of that stroke. (For instance, let's say the rectangle is drawn as 1px wide, but the mouse click region is actually 3px wide)
Is such a thing possible, or am I forced to increase the thickness of the Rectangle's stroke?
Hacky solution:
put a "transparent" rectangle in the same place, and make your rectangle IsHitTestVisible="False"
<Rectangle x:Name="Clickable"
Grid.Column="1"
MouseUp="HandleMouseUp"
Fill="#01FFFFFF"/>
<Rectangle Grid.Column="1"
Stroke="Red"
StrokeDashArray="4.0 4.0"
StrokeThickness="{Binding Path=CurrentThickness}"
IsHitTestVisible="False"
Visibility="{Binding Path=VisibleRectangle,
Converter={StaticResource VisibilityConverter}}"/>
This is what I ended up using, building on HighCore's answer. Note the margin used to move the displayed rectangle into the middle of the hit testing rectangle:
<!-- This border is displayed when XXX. -->
<!-- Note that the margin moves it into the middle of the hit testing
rectangle below. -->
<Rectangle Stroke="Red"
StrokeDashArray="4.0 4.0"
Margin="1"
StrokeThickness="{Binding Path=CurrentThickness}"
Visibility="{Binding Path=VisibleRectangle,
Converter={StaticResource VisibilityConverter}}" />
<!-- This border handles hit testing when XXX. -->
<Rectangle Panel.ZIndex="10"
StrokeThickness="3"
Stroke="Transparent"
MouseUp="HandleMouseUp"
Visibility="{Binding Path=VisibleRectangle,
Converter={StaticResource VisibilityConverter}}" />

Categories

Resources