diff --git a/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj b/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj
index c3982a685b1..6c5fe2387e6 100644
--- a/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj
+++ b/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj
@@ -832,9 +832,6 @@
MarkdownTextBlockPage.xaml
-
- TileControlPage.xaml
-
RadialProgressBarPage.xaml
@@ -1245,10 +1242,6 @@
MSBuild:Compile
Designer
-
- MSBuild:Compile
- Designer
-
MSBuild:Compile
Designer
diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/TileControl/TileControl.bind b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/TileControl/TileControl.bind
index 81ae40efb10..5a762c40c9e 100644
--- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/TileControl/TileControl.bind
+++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/TileControl/TileControl.bind
@@ -2,75 +2,34 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
+ xmlns:ani="using:Microsoft.Toolkit.Uwp.UI.Animations"
+ xmlns:media="using:Microsoft.Toolkit.Uwp.UI.Media"
+ xmlns:i="using:Microsoft.Xaml.Interactivity"
+ xmlns:b="using:Microsoft.Xaml.Interactions.Core"
+ xmlns:tb="using:Microsoft.Toolkit.Uwp.UI.Behaviors"
mc:Ignorable="d">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/TileControl/TileControlPage.xaml b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/TileControl/TileControlPage.xaml
deleted file mode 100644
index 633ab8d8920..00000000000
--- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/TileControl/TileControlPage.xaml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/TileControl/TileControlPage.xaml.cs b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/TileControl/TileControlPage.xaml.cs
deleted file mode 100644
index 91dc562f839..00000000000
--- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/TileControl/TileControlPage.xaml.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using Microsoft.Toolkit.Uwp.SampleApp.Models;
-using Windows.UI.Xaml.Navigation;
-
-namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages
-{
- public sealed partial class TileControlPage
- {
- public TileControlPage()
- {
- InitializeComponent();
- }
- }
-}
diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/XamlOnlyPage.xaml b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/XamlOnlyPage.xaml
index 2a74f960039..6e627244084 100644
--- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/XamlOnlyPage.xaml
+++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/XamlOnlyPage.xaml
@@ -46,6 +46,7 @@
+
@@ -60,12 +61,16 @@
+
+
+
+
diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json
index 766ba4b922f..19cb315e2dc 100644
--- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json
+++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json
@@ -205,11 +205,10 @@
},
{
"Name": "TileControl",
- "Type": "TileControlPage",
"Subcategory": "Layout",
"About": "A ContentControl that show an image repeated many times.The control can be synchronized with a Scrollviewer and animated easily",
"CodeUrl": "https://github.com/windows-toolkit/WindowsCommunityToolkit/tree/master/Microsoft.Toolkit.Uwp.UI.Controls.Core/TileControl",
- "XamlCodeFile": "TileControl.bind",
+ "XamlCodeFile": "/SamplePages/TileControl/TileControl.bind",
"Icon": "/SamplePages/TileControl/TileControl.png",
"DocumentationUrl": "https://raw.githubusercontent.com/MicrosoftDocs/WindowsCommunityToolkitDocs/master/docs/controls/TileControl.md"
},
diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Core/TileControl/TileControl.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Core/TileControl/TileControl.cs
index 20df3bf2c04..e593147d06f 100644
--- a/Microsoft.Toolkit.Uwp.UI.Controls.Core/TileControl/TileControl.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Controls.Core/TileControl/TileControl.cs
@@ -22,6 +22,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
/// A ContentControl that show an image repeated many times.
/// The control can be synchronized with a ScrollViewer and animated easily.
///
+ [Obsolete("The TileControl will be removed in a future update. Please look at the TilesBrush for static backgrounds, animating a SurfaceBrushFactory element for a scrolling tiled background, or the ParallaxView element for background effects for a container being scrolled.")]
public partial class TileControl : ContentControl
{
///
diff --git a/Microsoft.Toolkit.Uwp.UI.Media/Animations/Abstract/EffectAnimation{TEffect,TValue,TKeyFrame}.cs b/Microsoft.Toolkit.Uwp.UI.Media/Animations/Abstract/EffectAnimation{TEffect,TValue,TKeyFrame}.cs
index 7b9e3481129..9237b44d827 100644
--- a/Microsoft.Toolkit.Uwp.UI.Media/Animations/Abstract/EffectAnimation{TEffect,TValue,TKeyFrame}.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Media/Animations/Abstract/EffectAnimation{TEffect,TValue,TKeyFrame}.cs
@@ -23,7 +23,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Animations
///
/// The actual type of keyframe values in use.
public abstract class EffectAnimation : Animation
- where TEffect : class, IPipelineEffect
+ where TEffect : class, IBrushEffect
where TKeyFrame : unmanaged
{
///
diff --git a/Microsoft.Toolkit.Uwp.UI.Media/Animations/Brushes/AnchorPointBrushAnimation.cs b/Microsoft.Toolkit.Uwp.UI.Media/Animations/Brushes/AnchorPointBrushAnimation.cs
new file mode 100644
index 00000000000..33327563f63
--- /dev/null
+++ b/Microsoft.Toolkit.Uwp.UI.Media/Animations/Brushes/AnchorPointBrushAnimation.cs
@@ -0,0 +1,25 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Numerics;
+using Microsoft.Toolkit.Uwp.UI.Media;
+using Windows.UI.Composition;
+
+namespace Microsoft.Toolkit.Uwp.UI.Animations
+{
+ ///
+ /// An anchor point animation working on a .
+ ///
+ public sealed class AnchorPointBrushAnimation : EffectAnimation
+ {
+ ///
+ protected override string ExplicitTarget => nameof(CompositionSurfaceBrush.AnchorPoint);
+
+ ///
+ protected override (Vector2?, Vector2?) GetParsedValues()
+ {
+ return (To?.ToVector2(), From?.ToVector2());
+ }
+ }
+}
diff --git a/Microsoft.Toolkit.Uwp.UI.Media/Animations/Brushes/CenterPointBrushAnimation.cs b/Microsoft.Toolkit.Uwp.UI.Media/Animations/Brushes/CenterPointBrushAnimation.cs
new file mode 100644
index 00000000000..7f586278526
--- /dev/null
+++ b/Microsoft.Toolkit.Uwp.UI.Media/Animations/Brushes/CenterPointBrushAnimation.cs
@@ -0,0 +1,25 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Numerics;
+using Microsoft.Toolkit.Uwp.UI.Media;
+using Windows.UI.Composition;
+
+namespace Microsoft.Toolkit.Uwp.UI.Animations
+{
+ ///
+ /// A center point animation working on a .
+ ///
+ public sealed class CenterPointBrushAnimation : EffectAnimation
+ {
+ ///
+ protected override string ExplicitTarget => nameof(CompositionSurfaceBrush.CenterPoint);
+
+ ///
+ protected override (Vector2?, Vector2?) GetParsedValues()
+ {
+ return (To?.ToVector2(), From?.ToVector2());
+ }
+ }
+}
diff --git a/Microsoft.Toolkit.Uwp.UI.Media/Animations/Brushes/OffsetBrushAnimation.cs b/Microsoft.Toolkit.Uwp.UI.Media/Animations/Brushes/OffsetBrushAnimation.cs
new file mode 100644
index 00000000000..a3c23121810
--- /dev/null
+++ b/Microsoft.Toolkit.Uwp.UI.Media/Animations/Brushes/OffsetBrushAnimation.cs
@@ -0,0 +1,25 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Numerics;
+using Microsoft.Toolkit.Uwp.UI.Media;
+using Windows.UI.Composition;
+
+namespace Microsoft.Toolkit.Uwp.UI.Animations
+{
+ ///
+ /// An offset animation working on a .
+ ///
+ public sealed class OffsetBrushAnimation : EffectAnimation
+ {
+ ///
+ protected override string ExplicitTarget => nameof(CompositionSurfaceBrush.Offset);
+
+ ///
+ protected override (Vector2?, Vector2?) GetParsedValues()
+ {
+ return (To?.ToVector2(), From?.ToVector2());
+ }
+ }
+}
diff --git a/Microsoft.Toolkit.Uwp.UI.Media/Animations/Brushes/RotationAngleInDegreesBrushAnimation.cs b/Microsoft.Toolkit.Uwp.UI.Media/Animations/Brushes/RotationAngleInDegreesBrushAnimation.cs
new file mode 100644
index 00000000000..484d1ffee14
--- /dev/null
+++ b/Microsoft.Toolkit.Uwp.UI.Media/Animations/Brushes/RotationAngleInDegreesBrushAnimation.cs
@@ -0,0 +1,24 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.Toolkit.Uwp.UI.Media;
+using Windows.UI.Composition;
+
+namespace Microsoft.Toolkit.Uwp.UI.Animations
+{
+ ///
+ /// A rotation animation working on a .
+ ///
+ public sealed class RotationAngleInDegreesBrushAnimation : EffectAnimation
+ {
+ ///
+ protected override string ExplicitTarget => nameof(CompositionSurfaceBrush.RotationAngleInDegrees);
+
+ ///
+ protected override (double?, double?) GetParsedValues()
+ {
+ return (To, From);
+ }
+ }
+}
diff --git a/Microsoft.Toolkit.Uwp.UI.Media/Animations/Brushes/RotationBrushAnimation.cs b/Microsoft.Toolkit.Uwp.UI.Media/Animations/Brushes/RotationBrushAnimation.cs
new file mode 100644
index 00000000000..a2bbb9ba1e9
--- /dev/null
+++ b/Microsoft.Toolkit.Uwp.UI.Media/Animations/Brushes/RotationBrushAnimation.cs
@@ -0,0 +1,24 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.Toolkit.Uwp.UI.Media;
+using Windows.UI.Composition;
+
+namespace Microsoft.Toolkit.Uwp.UI.Animations
+{
+ ///
+ /// A rotation animation working on a .
+ ///
+ public sealed class RotationBrushAnimation : EffectAnimation
+ {
+ ///
+ protected override string ExplicitTarget => nameof(CompositionSurfaceBrush.RotationAngle);
+
+ ///
+ protected override (double?, double?) GetParsedValues()
+ {
+ return (To, From);
+ }
+ }
+}
diff --git a/Microsoft.Toolkit.Uwp.UI.Media/Animations/Brushes/ScaleBrushAnimation.cs b/Microsoft.Toolkit.Uwp.UI.Media/Animations/Brushes/ScaleBrushAnimation.cs
new file mode 100644
index 00000000000..156b7d5c67e
--- /dev/null
+++ b/Microsoft.Toolkit.Uwp.UI.Media/Animations/Brushes/ScaleBrushAnimation.cs
@@ -0,0 +1,25 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Numerics;
+using Microsoft.Toolkit.Uwp.UI.Media;
+using Windows.UI.Composition;
+
+namespace Microsoft.Toolkit.Uwp.UI.Animations
+{
+ ///
+ /// A scale animation working on a .
+ ///
+ public sealed class ScaleBrushAnimation : EffectAnimation
+ {
+ ///
+ protected override string ExplicitTarget => nameof(CompositionSurfaceBrush.Scale);
+
+ ///
+ protected override (Vector2?, Vector2?) GetParsedValues()
+ {
+ return (To?.ToVector2(), From?.ToVector2());
+ }
+ }
+}
diff --git a/Microsoft.Toolkit.Uwp.UI.Media/Effects/BorderEffect.cs b/Microsoft.Toolkit.Uwp.UI.Media/Effects/BorderEffect.cs
new file mode 100644
index 00000000000..8fe851ed0bd
--- /dev/null
+++ b/Microsoft.Toolkit.Uwp.UI.Media/Effects/BorderEffect.cs
@@ -0,0 +1,35 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using Microsoft.Graphics.Canvas;
+using Microsoft.Toolkit.Uwp.UI.Media.Pipelines;
+
+#nullable enable
+
+namespace Microsoft.Toolkit.Uwp.UI.Media
+{
+ ///
+ /// A border effect useful for tiling a surface, it is not animatable directly, animate the incoming surface.
+ ///
+ /// This effect maps to the Win2D effect
+ public sealed class BorderEffect : PipelineEffect
+ {
+ ///
+ /// Gets or sets the wrapping behavior in the horizontal direction.
+ ///
+ public CanvasEdgeBehavior ExtendX { get; set; } = CanvasEdgeBehavior.Wrap;
+
+ ///
+ /// Gets or sets the wrapping behavior in the vertical direction.
+ ///
+ public CanvasEdgeBehavior ExtendY { get; set; } = CanvasEdgeBehavior.Wrap;
+
+ ///
+ public override PipelineBuilder AppendToBuilder(PipelineBuilder builder)
+ {
+ return builder.Border(ExtendX, ExtendY);
+ }
+ }
+}
diff --git a/Microsoft.Toolkit.Uwp.UI.Media/Effects/Interfaces/IBrushEffect.cs b/Microsoft.Toolkit.Uwp.UI.Media/Effects/Interfaces/IBrushEffect.cs
new file mode 100644
index 00000000000..d84bd1dd876
--- /dev/null
+++ b/Microsoft.Toolkit.Uwp.UI.Media/Effects/Interfaces/IBrushEffect.cs
@@ -0,0 +1,22 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.Toolkit.Uwp.UI.Media.Pipelines;
+using Windows.UI.Composition;
+
+#nullable enable
+
+namespace Microsoft.Toolkit.Uwp.UI.Media
+{
+ ///
+ /// The base for all the builder effects to be used in a .
+ ///
+ public interface IBrushEffect
+ {
+ ///
+ /// Gets the current instance, if one is in use.
+ ///
+ CompositionBrush? Brush { get; }
+ }
+}
diff --git a/Microsoft.Toolkit.Uwp.UI.Media/Effects/Interfaces/IPipelineEffect.cs b/Microsoft.Toolkit.Uwp.UI.Media/Effects/Interfaces/IPipelineEffect.cs
index c4fa00040ed..7e81c3a1a3f 100644
--- a/Microsoft.Toolkit.Uwp.UI.Media/Effects/Interfaces/IPipelineEffect.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Media/Effects/Interfaces/IPipelineEffect.cs
@@ -12,13 +12,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Media
///
/// The base for all the builder effects to be used in a .
///
- public interface IPipelineEffect
+ public interface IPipelineEffect : IBrushEffect
{
- ///
- /// Gets the current instance, if one is in use.
- ///
- CompositionBrush? Brush { get; }
-
///
/// Appends the current effect to the input instance.
///
diff --git a/Microsoft.Toolkit.Uwp.UI.Media/Pipelines/PipelineBuilder.Effects.cs b/Microsoft.Toolkit.Uwp.UI.Media/Pipelines/PipelineBuilder.Effects.cs
index bc0980e6e35..0bf1911f064 100644
--- a/Microsoft.Toolkit.Uwp.UI.Media/Pipelines/PipelineBuilder.Effects.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Media/Pipelines/PipelineBuilder.Effects.cs
@@ -7,10 +7,12 @@
using System.Diagnostics.Contracts;
using System.Linq;
using System.Threading.Tasks;
+using Microsoft.Graphics.Canvas;
using Microsoft.Graphics.Canvas.Effects;
using Windows.Graphics.Effects;
using Windows.UI;
using Windows.UI.Composition;
+using CanvasBorderEffect = Microsoft.Graphics.Canvas.Effects.BorderEffect;
using CanvasExposureEffect = Microsoft.Graphics.Canvas.Effects.ExposureEffect;
using CanvasGrayscaleEffect = Microsoft.Graphics.Canvas.Effects.GrayscaleEffect;
using CanvasHueRotationEffect = Microsoft.Graphics.Canvas.Effects.HueRotationEffect;
@@ -104,6 +106,25 @@ public PipelineBuilder Blur(float blur, out EffectAnimation animation, Ef
return new PipelineBuilder(this, Factory, new[] { $"{id}.{nameof(GaussianBlurEffect.BlurAmount)}" });
}
+ ///
+ /// Adds a new to the current pipeline
+ ///
+ /// The in the horizontal direction
+ /// The in the vertical direction
+ /// A new instance to use to keep adding new effects
+ [Pure]
+ public PipelineBuilder Border(CanvasEdgeBehavior extendX, CanvasEdgeBehavior extendY)
+ {
+ async ValueTask Factory() => new CanvasBorderEffect
+ {
+ ExtendX = extendX,
+ ExtendY = extendY,
+ Source = await this.sourceProducer()
+ };
+
+ return new PipelineBuilder(this, Factory);
+ }
+
///
/// Adds a new to the current pipeline
///
diff --git a/Microsoft.Toolkit.Uwp.UI.Media/Pipelines/PipelineBuilder.Initialization.cs b/Microsoft.Toolkit.Uwp.UI.Media/Pipelines/PipelineBuilder.Initialization.cs
index 92f3bb86f62..32a83bd4b45 100644
--- a/Microsoft.Toolkit.Uwp.UI.Media/Pipelines/PipelineBuilder.Initialization.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Media/Pipelines/PipelineBuilder.Initialization.cs
@@ -15,6 +15,7 @@
using Windows.UI.Composition;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Hosting;
+using CanvasBorderEffect = Microsoft.Graphics.Canvas.Effects.BorderEffect;
namespace Microsoft.Toolkit.Uwp.UI.Media.Pipelines
{
@@ -298,7 +299,7 @@ public static PipelineBuilder FromTiles(Uri uri, DpiMode dpiMode = DpiMode.Displ
{
var image = FromImage(uri, dpiMode, cacheMode);
- async ValueTask Factory() => new BorderEffect
+ async ValueTask Factory() => new CanvasBorderEffect
{
ExtendX = CanvasEdgeBehavior.Wrap,
ExtendY = CanvasEdgeBehavior.Wrap,
diff --git a/Microsoft.Toolkit.Uwp.UI.Media/Visuals/SurfaceBrushFactory.BrushProperties.cs b/Microsoft.Toolkit.Uwp.UI.Media/Visuals/SurfaceBrushFactory.BrushProperties.cs
new file mode 100644
index 00000000000..0ae8f141a95
--- /dev/null
+++ b/Microsoft.Toolkit.Uwp.UI.Media/Visuals/SurfaceBrushFactory.BrushProperties.cs
@@ -0,0 +1,132 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Numerics;
+using System.Threading.Tasks;
+using Microsoft.Toolkit.Uwp.UI.Media.Pipelines;
+using Windows.Foundation;
+using Windows.UI.Composition;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Markup;
+using Windows.UI.Xaml.Media;
+
+namespace Microsoft.Toolkit.Uwp.UI.Media
+{
+ ///
+ /// Contains the properties for passthrue to the .
+ ///
+ public sealed partial class SurfaceBrushFactory
+ {
+ ///
+ /// Gets or sets the property of the underlying .
+ ///
+ public Point AnchorPoint
+ {
+ get => _brush.AnchorPoint.ToPoint();
+ set => _brush.AnchorPoint = value.ToVector2();
+ }
+
+ ///
+ /// Gets or sets the property of the underlying .
+ ///
+ public CompositionBitmapInterpolationMode BitmapInterpolationMode
+ {
+ get => _brush.BitmapInterpolationMode;
+ set => _brush.BitmapInterpolationMode = value;
+ }
+
+ ///
+ /// Gets or sets the property of the underlying .
+ ///
+ public Point CenterPoint
+ {
+ get => _brush.CenterPoint.ToPoint();
+ set => _brush.CenterPoint = value.ToVector2();
+ }
+
+ ///
+ /// Gets or sets the property of the underlying .
+ ///
+ public double HorizontalAlignmentRatio
+ {
+ get => _brush.HorizontalAlignmentRatio;
+ set => _brush.HorizontalAlignmentRatio = (float)Math.Clamp(value, 0.0f, 1.0f);
+ }
+
+ ///
+ /// Gets or sets the property of the underlying .
+ ///
+ public Point Offset
+ {
+ get => _brush.Offset.ToPoint();
+ set => _brush.Offset = value.ToVector2();
+ }
+
+ ///
+ /// Gets or sets the property of the underlying .
+ ///
+ public double RotationAngle
+ {
+ get => _brush.RotationAngle;
+ set => _brush.RotationAngle = (float)value;
+ }
+
+ ///
+ /// Gets or sets the property of the underlying .
+ ///
+ public double RotationAngleInDegrees
+ {
+ get => _brush.RotationAngleInDegrees;
+ set => _brush.RotationAngleInDegrees = (float)value;
+ }
+
+ ///
+ /// Gets or sets the property of the underlying .
+ ///
+ public Point Scale
+ {
+ get => _brush.Scale.ToPoint();
+ set => _brush.Scale = value.ToVector2();
+ }
+
+ ///
+ /// Gets or sets a value indicating whether property of the underlying is set.
+ ///
+ public bool SnapToPixels
+ {
+ get => _brush.SnapToPixels;
+ set => _brush.SnapToPixels = value;
+ }
+
+ ///
+ /// Gets or sets the property of the underlying .
+ ///
+ public CompositionStretch Stretch
+ {
+ get => _brush.Stretch;
+ set => _brush.Stretch = value;
+ }
+
+ ///
+ /// Gets or sets the property of the underlying .
+ ///
+ public Matrix3x2 TransformMatrix
+ {
+ get => _brush.TransformMatrix;
+ set => _brush.TransformMatrix = value;
+ }
+
+ ///
+ /// Gets or sets the property of the underlying .
+ ///
+ public double VerticalAlignmentRatio
+ {
+ get => _brush.VerticalAlignmentRatio;
+ set => _brush.VerticalAlignmentRatio = (float)Math.Clamp(value, 0.0f, 1.0f);
+ }
+
+ }
+}
diff --git a/Microsoft.Toolkit.Uwp.UI.Media/Visuals/SurfaceBrushFactory.cs b/Microsoft.Toolkit.Uwp.UI.Media/Visuals/SurfaceBrushFactory.cs
new file mode 100644
index 00000000000..f1f0381bad2
--- /dev/null
+++ b/Microsoft.Toolkit.Uwp.UI.Media/Visuals/SurfaceBrushFactory.cs
@@ -0,0 +1,109 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Microsoft.Toolkit.Uwp.UI.Media.Pipelines;
+using Windows.UI.Composition;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Markup;
+using Windows.UI.Xaml.Media;
+
+namespace Microsoft.Toolkit.Uwp.UI.Media
+{
+ ///
+ /// A builder type for a to apply to the visual of UI elements.
+ ///
+ [ContentProperty(Name = nameof(Effects))]
+ public sealed partial class SurfaceBrushFactory : PipelineVisualFactoryBase, IBrushEffect
+ {
+ private CompositionSurfaceBrush _brush;
+
+ ///
+ public CompositionBrush Brush => _brush;
+
+ private Uri _uri;
+
+ ///
+ /// Gets or sets the source of an image to use to start the Pipeline.
+ ///
+ public Uri Source
+ {
+ get
+ {
+ return _uri;
+ }
+
+ set
+ {
+ _uri = value;
+
+ if (_uri != null)
+ {
+ //// TODO: I think we want a few different options, like make this a provider and have another one to take the Win2D Path somehow maybe?
+ _brush = Window.Current.Compositor.CreateSurfaceBrush(LoadedImageSurface.StartLoadFromUri(_uri));
+ }
+ else
+ {
+ _brush = null;
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets the collection of effects to use in the current pipeline.
+ ///
+ public IList Effects
+ {
+ get
+ {
+ if (GetValue(EffectsProperty) is not IList effects)
+ {
+ effects = new List();
+
+ SetValue(EffectsProperty, effects);
+ }
+
+ return effects;
+ }
+ set => SetValue(EffectsProperty, value);
+ }
+
+ ///
+ /// Identifies the dependency property.
+ ///
+ public static readonly DependencyProperty EffectsProperty = DependencyProperty.Register(
+ nameof(Effects),
+ typeof(IList),
+ typeof(PipelineVisualFactory),
+ new PropertyMetadata(null));
+
+ ///
+ public override async ValueTask GetAttachedVisualAsync(UIElement element)
+ {
+ var visual = (SpriteVisual)await base.GetAttachedVisualAsync(element);
+
+ foreach (IPipelineEffect effect in Effects)
+ {
+ effect.NotifyCompositionBrushInUse(visual.Brush);
+ }
+
+ return visual;
+ }
+
+ ///
+ protected override PipelineBuilder OnPipelineRequested()
+ {
+ PipelineBuilder builder = PipelineBuilder.FromBrush(Brush);
+
+ foreach (IPipelineEffect effect in Effects)
+ {
+ builder = effect.AppendToBuilder(builder);
+ }
+
+ return builder;
+ }
+ }
+}