1. WPF有,而UWP沒有的圖片平鋪功能
在WPF中只要將ImageSource的TileMode屬性設定為Tile即可實作圖片的平鋪,具體可見WPF的這些檔案:
ImageBrush 類 (System.Windows.Media) _ Microsoft Docs
TileBrush 類 (System.Windows.Media) _ Microsoft Docs
TileBrush.TileMode 屬性 (System.Windows.Media) _ Microsoft Docs

WPF圖片平鋪功能我幾乎沒用過,只是作為基礎中的基礎知識記住了用法,我以為那么基礎的功能在UWP肯定有,根本不用懷疑,所以當我在UWP中發現這么基礎的東西居然沒有時真的嚇了一跳,

上圖左面是WPF版本的TileBrush,右邊是UWP版本,可以看到UWP版本功能少了一大半,
這么小的一個類,我覺得沒必要在這里做簡化吧,幸好圖片平鋪可以使用Win2D里的BorderEffect實作,

2. UWP中的圖片平鋪功能
<Grid>
<Rectangle x:Name="Background" />
</Grid>
假設有以上的XAML,要在名為Background的元素上應用合成畫筆,首先參考Win2D.uwp nuget包,然后參考官方檔案中 合成畫筆 的部分使用圖片創建一個合成畫筆:
var compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
var imageBrush = compositor.CreateSurfaceBrush();
var loadedSurface = LoadedImageSurface.StartLoadFromUri(new Uri("ms-appx:///110Strawberry.png"));
imageBrush.Surface = loadedSurface;
imageBrush.Stretch = CompositionStretch.None;
現在就差創建一個SpriteVisual并把它應用到Background的VisualTree上了,順便一提,是這張圖片:

不過要實作平鋪功能還需要創建一個BorderEffect:
var borderEffect = new BorderEffect
{
Source = new CompositionEffectSourceParameter("source")
};
var effectFactory = compositor.CreateEffectFactory(borderEffect);
var effectBrush = effectFactory.CreateBrush();
effectBrush.SetSourceParameter("source", imageBrush);
var sprite = compositor.CreateSpriteVisual();
sprite.Brush = effectBrush;
var backgroundVisual = ElementCompositionPreview.GetElementVisual(Background);
var bindSizeAnimation = compositor.CreateExpressionAnimation("backgroundVisual.Size");
bindSizeAnimation.SetReferenceParameter("backgroundVisual", backgroundVisual);
sprite.StartAnimation("Size", bindSizeAnimation);
ElementCompositionPreview.SetElementChildVisual(Background, sprite);
總之BorderEffect以imageBrush為Source,其它都保留默認值,將它它應用到Background的VisualTree上后效果如下:

這還不是我想要的平鋪效果,這是因為這時候ExtendX和ExtendY保持默認值的Clamp,這個型別會讓BorderEffect重復影像邊緣的屬性,如果要實作我想要的平鋪需要將這兩個屬性設定為Wrap:
borderEffect.ExtendX = CanvasEdgeBehavior.Wrap;
borderEffect.ExtendY = CanvasEdgeBehavior.Wrap;

居然不是從左上角開始平鋪的,和我的想法還是有出入,不過這種細節就算了,順便一提ExtendX和ExtendY還可以設定為Mirror,效果如下:

3. 系結Size
var backgroundVisual = ElementCompositionPreview.GetElementVisual(Background);
var bindSizeAnimation = compositor.CreateExpressionAnimation("backgroundVisual.Size");
bindSizeAnimation.SetReferenceParameter("backgroundVisual", backgroundVisual);
sprite.StartAnimation("Size", bindSizeAnimation);
最后順便提一下,上面的代碼中有這么一段代碼沒介紹到,這是用來動態地設定SpriteVisual的尺寸,ExpressionAnimation有一直運行和永不停止這兩個特性,創建ExpressionAnimation并在SpriteVisual上運行影片,實際上將SpriteVisual的Size永遠地系結為backgroundVisual 的Size的值,其實簡單地訂閱SizeChanged事件也能達到這個效果,代碼好像還少些,
4. 結語
這么簡單的功能居然都要這么多代碼,或者有更簡單的實作?不過凡事都有要辯證地看,幸好它這么復雜,又讓我水了一篇博客,
Stack Overflow有給出其它的方案,可以參考一下,
5. 參考
Border effect - Win32 apps _ Microsoft Docs
合成畫筆 - Windows UWP applications _ Microsoft Docs
【Win2D】【譯】Win2D 快速入門 - h82258652 - 博客園
基于關系的影片 - Windows UWP applications Microsoft Docs
c# - UWP - How to tile a background image - Stack Overflow
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/1702.html
標籤:UWP
