- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
在通用 Windows 应用程序中,我尝试使用背景图像(来自 ImageSource)并将其平铺在控件上。
XAML
<Grid x:Name="gridBackground">
<ContentPresenter />
</Grid>
C#
void UpdateBackground(ImageSource source)
{
// ...
gridBackground.Background = new ImageBrush {
ImageSource = source,
Stretch = Stretch.None
};
}
根据 MSDN ,ImageBrush继承自TileBrush。它甚至说:
Use for an ImageBrush include decorative effects for text, or tiled backgrounds for controls or layout containers.
如果禁用拉伸(stretch),我会假设这应该平铺图像,但是,唉,它只是在控件的中间绘制图像。我没有看到任何使其平铺的实际属性。
在WPF中,有一个TileMode可以设置属性和 ViewPort 来指定图 block 的尺寸。但这在通用平台下似乎不存在。
A previous question指的是 WinRT (Windows 8),但我希望有一个基于画笔的解决方案,而不是用图像填充 Canvas 。
如何使用 UWP 平铺背景图像?
最佳答案
A previous question refers to WinRT (Windows 8), but I'm hoping for a brush based solution, rather than filling a canvas with images.
目前,在 UWP 应用程序中以平铺模式显示背景图像只有两种解决方案,您知道的第一种是填充 Canvas 。
我使用的第二个是创建一个 Panel 并在其上绘制图像,这个想法源自 this article
此方法的作用是滥用我们在矩形中绘制重复线组的事实。首先,它尝试在顶部绘制一个与我们的图 block 高度相同的 block 。然后它向下复制该 block ,直到它到达底部。
我修改了一些代码并修复了一些问题:
public class TiledBackground : Panel
{
public ImageSource BackgroundImage
{
get { return (ImageSource)GetValue(BackgroundImageProperty); }
set { SetValue(BackgroundImageProperty, value); }
}
// Using a DependencyProperty as the backing store for BackgroundImage. This enables animation, styling, binding, etc...
public static readonly DependencyProperty BackgroundImageProperty =
DependencyProperty.Register("BackgroundImage", typeof(ImageSource), typeof(TiledBackground), new PropertyMetadata(null, BackgroundImageChanged));
private static void BackgroundImageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((TiledBackground)d).OnBackgroundImageChanged();
}
private static void DesignDataChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((TiledBackground)d).OnDesignDataChanged();
}
private ImageBrush backgroundImageBrush = null;
private bool tileImageDataRebuildNeeded = true;
private byte[] tileImagePixels = null;
private int tileImageWidth = 0;
private int tileImageHeight = 0;
private readonly BitmapPixelFormat bitmapPixelFormat = BitmapPixelFormat.Bgra8;
private readonly BitmapTransform bitmapTransform = new BitmapTransform();
private readonly BitmapAlphaMode bitmapAlphaMode = BitmapAlphaMode.Straight;
private readonly ExifOrientationMode exifOrientationMode = ExifOrientationMode.IgnoreExifOrientation;
private readonly ColorManagementMode coloManagementMode = ColorManagementMode.ColorManageToSRgb;
public TiledBackground()
{
this.backgroundImageBrush = new ImageBrush();
this.Background = backgroundImageBrush;
this.SizeChanged += TiledBackground_SizeChanged;
}
private async void TiledBackground_SizeChanged(object sender, SizeChangedEventArgs e)
{
await this.Render((int)e.NewSize.Width, (int)e.NewSize.Height);
}
private async void OnBackgroundImageChanged()
{
tileImageDataRebuildNeeded = true;
await Render((int)this.ActualWidth, (int)this.ActualHeight);
}
private async void OnDesignDataChanged()
{
tileImageDataRebuildNeeded = true;
await Render((int)this.ActualWidth, (int)this.ActualHeight);
}
private async Task RebuildTileImageData()
{
BitmapImage image = BackgroundImage as BitmapImage;
if ((image != null) && (!DesignMode.DesignModeEnabled))
{
string imgUri = image.UriSource.OriginalString;
if (!imgUri.Contains("ms-appx:///"))
{
imgUri += "ms-appx:///";
}
var imageSource = new Uri(imgUri);
StorageFile storageFile = await StorageFile.GetFileFromApplicationUriAsync(imageSource);
using (var imageStream = await storageFile.OpenAsync(FileAccessMode.Read))
{
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(imageStream);
var pixelDataProvider = await decoder.GetPixelDataAsync(this.bitmapPixelFormat, this.bitmapAlphaMode,
this.bitmapTransform, this.exifOrientationMode, this.coloManagementMode
);
this.tileImagePixels = pixelDataProvider.DetachPixelData();
this.tileImageHeight = (int)decoder.PixelHeight;
this.tileImageWidth = (int)decoder.PixelWidth;
}
}
}
private byte[] CreateBackgroud(int width, int height)
{
int bytesPerPixel = this.tileImagePixels.Length / (this.tileImageWidth * this.tileImageHeight);
byte[] data = new byte[width * height * bytesPerPixel];
int y = 0;
int fullTileInRowCount = width / tileImageWidth;
int tileRowLength = tileImageWidth * bytesPerPixel;
//Stage 1: Go line by line and create a block of our pattern
//Stop when tile image height or required height is reached
while ((y < height) && (y < tileImageHeight))
{
int tileIndex = y * tileImageWidth * bytesPerPixel;
int dataIndex = y * width * bytesPerPixel;
//Copy the whole line from tile at once
for (int i = 0; i < fullTileInRowCount; i++)
{
Array.Copy(tileImagePixels, tileIndex, data, dataIndex, tileRowLength);
dataIndex += tileRowLength;
}
//Copy the rest - if there is any
//Length will evaluate to 0 if all lines were copied without remainder
Array.Copy(tileImagePixels, tileIndex, data, dataIndex,
(width - fullTileInRowCount * tileImageWidth) * bytesPerPixel);
y++; //Next line
}
//Stage 2: Now let's copy those whole blocks from top to bottom
//If there is not enough space to copy the whole block, skip to stage 3
int rowLength = width * bytesPerPixel;
int blockLength = this.tileImageHeight * rowLength;
while (y <= (height - tileImageHeight))
{
int dataBaseIndex = y * width * bytesPerPixel;
Array.Copy(data, 0, data, dataBaseIndex, blockLength);
y += tileImageHeight;
}
//Copy the rest line by line
//Use previous lines as source
for (int row = y; row < height; row++)
Array.Copy(data, (row - tileImageHeight) * rowLength, data, row * rowLength, rowLength);
return data;
}
private async Task Render(int width, int height)
{
Stopwatch fullsw = Stopwatch.StartNew();
if (tileImageDataRebuildNeeded)
await RebuildTileImageData();
if ((height > 0) && (width > 0))
{
using (var randomAccessStream = new InMemoryRandomAccessStream())
{
Stopwatch sw = Stopwatch.StartNew();
var backgroundPixels = CreateBackgroud(width, height);
sw.Stop();
Debug.WriteLine("Background generation finished: {0} ticks - {1} ms", sw.ElapsedTicks, sw.ElapsedMilliseconds);
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, randomAccessStream);
encoder.SetPixelData(this.bitmapPixelFormat, this.bitmapAlphaMode, (uint)width, (uint)height, 96, 96, backgroundPixels);
await encoder.FlushAsync();
if (this.backgroundImageBrush.ImageSource == null)
{
BitmapImage bitmapImage = new BitmapImage();
randomAccessStream.Seek(0);
bitmapImage.SetSource(randomAccessStream);
this.backgroundImageBrush.ImageSource = bitmapImage;
}
else ((BitmapImage)this.backgroundImageBrush.ImageSource).SetSource(randomAccessStream);
}
}
else this.backgroundImageBrush.ImageSource = null;
fullsw.Stop();
Debug.WriteLine("Background rendering finished: {0} ticks - {1} ms", fullsw.ElapsedTicks, fullsw.ElapsedMilliseconds);
}
}
用法:
<Grid x:Name="rootGrid" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<tileCtrl:TiledBackground
BackgroundImage="Assets/avatar1.png"
Width="{Binding ActualWidth, ElementName=rootGrid}" Height="{Binding ActualHeight, ElementName=rootGrid}"/>
</Grid>
查看解决方案 Github
关于c# - UWP - 如何平铺背景图像?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35456324/
uwp 和非 uwp 应用程序之间是否可以进行通信。我的非uwp是一个提供服务的后台任务。我想在 uwp 应用程序中调用该非 uwp 服务。 如何调用电话? AppServiceConnection
我正在开发一个应用程序,该应用程序旨在在具有多个显示器(从 1 到 3必要)在每个监视器上,每个监视器都显示不同的 View 。 就我所见,UWP 并不自然适用于这种情况。我设法使用 CoreAppl
我正在尝试对UWP应用使用broadFileSystemAccess功能,但是package.appxmanifest的功能列表中未列出broadFileSystemAccess功能。 我的最低和最高
有时我有一个打开的流或一个事件的队列,必须在应用程序关闭时正确处理。在 WPF 应用程序中,我可以在应用程序上使用 Unloading 事件,但在 UWP 中我注意到这样的事件不存在。 我如何可靠地做
http://wikisend.com/download/880354/UWP_Server.zip 我已将代码上传至上述网址。 它是 UWP 中的客户端和服务器应用程序。这里客户端和服务器都在同一个
大家好 我知道这个问题(Chromium working on UWP)之前(2015/2016)有人问过,想看看有没有更新 我正在尝试在 UWP 应用程序中使用 CEF3 构建,但在运行该应用程序时
我目前正在构建一个应用程序,它可以使用 Windows 游戏 DVR 在某个时刻开始录制屏幕。该录音机在完成录音时将应用程序名称作为文件名。 我发现了如何使用 Applicationview.GetF
我已使用 Desktop App Converter 将我的 WPF 应用程序转换为 appx 包。我需要在资源管理器上下文菜单中有一个项目。 IE。用户右键单击文件并在主菜单中看到我的项目“对应用程
我想稍微修改一个 Button 控件(添加描述)。在哪里可以找到 UWP 控件的默认控件模板? 最佳答案 似乎可以在以下位置找到它们: C:\Program Files (x86)\Windows K
我想通过 UWP 应用访问 windows10 注册表项。 键为:\HKEY_LOCAL_MACHINE\SOFTWARE\MyCompanyName\MyName 我找不到任何函数调用来完成它。 请
我开发了一个 UWP appx,它可以安装在 cmd.exe 提示符中: C:\test>myapp.appx 但是在安装过程中会弹出一个 Windows GUI。 有没有什么方法 使用 Silent
在我的 UWP 应用程序中,如何通过 UpdateTask 中的代码进行调试? VS 2017 中的“生命周期事件”下拉菜单似乎没有提供触发此类后台任务的选项。有办法实现吗? 最佳答案 首先是关于 U
我尝试在 VS 2017 中创建一个 UWP 应用程序包。 创建时我收到一条神秘的错误消息:严重性代码描述项目文件行抑制状态错误 0xdef00532 - 资源“Files/Assets/Square
我有一个 TextBlock在我的应用程序中。我要办理pinch in & out在它上面调整字体的大小。当ManipulationDelta事件触发我检查Scale属性(property),但大多数
为什么默认选择的索引不起作用?它因平台异常而崩溃: RumTime 错误: Exception thrown at 0x00007FFDEF7F7788 (KernelBase.dll) in ab
有没有办法在同一个包中的 UWP 应用程序和桌面桥应用程序之间共享互斥锁?它们似乎有不同的命名空间;使用相同的名称不会在进程之间产生相同的对象。根据 WinObj,UWP 应用程序的对象是,存储在 A
有什么方法可以检测当前的 UWP 要退出 ? (由用户关闭或终止进程) 我想向服务器发送一些关于应用程序将断开连接的请求,还想在退出之前保存一些数据。 最佳答案 无法检测这种情况或阻止用户终止您的应用
我正在使用 XAML 和 C# 开发通用 Windows 平台应用程序。我想在 UWP 中更改焦点上 TextBox 的边框颜色。 在此先感谢您的帮助。 最佳答案 其实实现起来很简单,按照以下步骤即可
是否可以在 UWP 应用中更改甚至隐藏鼠标指针? 我唯一能找到的是: Windows.UI.Xaml.Window.Current.CoreWindow.PointerCursor = null; 但
我是一名优秀的程序员,十分优秀!