Skip to content

Commit

Permalink
feat: 添加了 BorderContentAdapter
Browse files Browse the repository at this point in the history
  • Loading branch information
SlimeNull committed Aug 30, 2024
1 parent b44c2cc commit 707beda
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 34 deletions.
62 changes: 31 additions & 31 deletions EleCho.WpfSuite/Controls/Border.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public class Border : System.Windows.Controls.Border
/// <summary>
/// A geometry to clip the content of this border correctly
/// </summary>
public Geometry ContentClip
public Geometry? ContentClip
{
get { return (Geometry)GetValue(ContentClipProperty); }
set { SetValue(ContentClipProperty, value); }
Expand All @@ -33,37 +33,10 @@ public Geometry ContentClip
public static readonly DependencyProperty ContentClipProperty =
ContentClipPropertyKey.DependencyProperty;

private Geometry? CalculateContentClip()
{
var borderThickness = BorderThickness;
var cornerRadius = CornerRadius;
var renderSize = RenderSize;

var contentWidth = renderSize.Width - borderThickness.Left - borderThickness.Right;
var contentHeight = renderSize.Height - borderThickness.Top - borderThickness.Bottom;

if (contentWidth > 0 && contentHeight > 0)
{
var rect = new Rect(0, 0, contentWidth, contentHeight);
var radii = new Radii(cornerRadius, borderThickness, false);

var contentGeometry = new StreamGeometry();
using StreamGeometryContext ctx = contentGeometry.Open();
GenerateGeometry(ctx, rect, radii);

contentGeometry.Freeze();
return contentGeometry;
}
else
{
return null;
}
}

/// <inheritdoc/>
protected override Size ArrangeOverride(Size finalSize)
{
SetValue(ContentClipPropertyKey, CalculateContentClip());
SetValue(ContentClipPropertyKey, CalculateContentClip(this));

return base.ArrangeOverride(finalSize);
}
Expand Down Expand Up @@ -93,14 +66,41 @@ protected override Geometry GetLayoutClip(Size layoutSlotSize)
}
}

private static Geometry? CalculateContentClip(System.Windows.Controls.Border border)
{
var borderThickness = border.BorderThickness;
var cornerRadius = border.CornerRadius;
var renderSize = border.RenderSize;

var contentWidth = renderSize.Width - borderThickness.Left - borderThickness.Right;
var contentHeight = renderSize.Height - borderThickness.Top - borderThickness.Bottom;

if (contentWidth > 0 && contentHeight > 0)
{
var rect = new Rect(0, 0, contentWidth, contentHeight);
var radii = new Radii(cornerRadius, borderThickness, false);

var contentGeometry = new StreamGeometry();
using StreamGeometryContext ctx = contentGeometry.Open();
GenerateGeometry(ctx, rect, radii);

contentGeometry.Freeze();
return contentGeometry;
}
else
{
return null;
}
}

/// <summary>
/// Generates a StreamGeometry.
/// </summary>
/// <param name="ctx">An already opened StreamGeometryContext.</param>
/// <param name="rect">Rectangle for geometry conversion.</param>
/// <param name="radii">Corner radii.</param>
/// <returns>Result geometry.</returns>
private static void GenerateGeometry(StreamGeometryContext ctx, Rect rect, Radii radii)
internal static void GenerateGeometry(StreamGeometryContext ctx, Rect rect, Radii radii)
{
//
// compute the coordinates of the key points
Expand Down Expand Up @@ -221,7 +221,7 @@ private static void GenerateGeometry(StreamGeometryContext ctx, Rect rect, Radii
}


private struct Radii
internal struct Radii
{
internal Radii(CornerRadius radii, Thickness borders, bool outer)
{
Expand Down
56 changes: 56 additions & 0 deletions EleCho.WpfSuite/Controls/BorderContentAdapter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace EleCho.WpfSuite
{
/// <summary>
/// Auto clip content depends on the parent border
/// </summary>
public class BorderContentAdapter : Decorator
{
static BorderContentAdapter()
{
ClipToBoundsProperty.OverrideMetadata(typeof(BorderContentAdapter), new PropertyMetadata(true));
}

private static Geometry? CalculateBorderContentClip(System.Windows.Controls.Border border, Size contentSize)
{
if (contentSize.Width <= 0 ||
contentSize.Height <= 0)
{
return null;
}

var rect = new Rect(0, 0, contentSize.Width, contentSize.Height);
var radii = new Border.Radii(border.CornerRadius, border.BorderThickness, false);

var contentGeometry = new StreamGeometry();
using StreamGeometryContext ctx = contentGeometry.Open();
Border.GenerateGeometry(ctx, rect, radii);

contentGeometry.Freeze();
return contentGeometry;
}

/// <inheritdoc/>
protected override Geometry GetLayoutClip(Size layoutSlotSize)
{
var renderSize = RenderSize;

if (Parent is EleCho.WpfSuite.Border border &&
CalculateBorderContentClip(border, renderSize) is { } borderContentClip)
{
return borderContentClip;
}
else if (Parent is System.Windows.Controls.Border nativeBorder &&
CalculateBorderContentClip(nativeBorder, renderSize) is { } nativeBorderContentClip)
{
return nativeBorderContentClip;
}

return base.GetLayoutClip(layoutSlotSize);
}
}

}
8 changes: 5 additions & 3 deletions WpfTest/Tests/TempPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -251,14 +251,16 @@

<RepeatButton Content="QWQ"/>

<ws:Border ClipToBounds="True"
<Border ClipToBounds="True"
CornerRadius="5 10 15 20"
BorderThickness="3"
BorderBrush="Red"
MaxWidth="200"
Name="testClip">
<Image Source="/Assets/TestImage2.jpg"/>
</ws:Border>
<ws:BorderContentAdapter>
<Image Source="/Assets/TestImage2.jpg"/>
</ws:BorderContentAdapter>
</Border>

<ws:Border Width="200" Height="50"
BorderBrush="{DynamicResource {x:Static wsd:FluentResource.TextControlElevationBorderFocusedBrush}}"
Expand Down

0 comments on commit 707beda

Please sign in to comment.