Windows Universal应用程序通过单个代码库定位多种类型的设备。如果您参考Windows 8.1或Windows 10,请指定其他标签。
使用鼠标和触摸在 ScrollViewer 中的 Canvas 中绘制矩形
我在 ScrollViewer 中得到了一个 Canvas。 我在 ScrollViewer 中有一个 Canvas。 <ScrollViewer x:Name="svWorkSpace" Visibility="Collapsed" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" Tapped="svWorkSpace_Tapped" PointerPressed="svWorkSpace_PointerPressed" PointerMoved="svWorkSpace_PointerMoved" PointerReleased="svWorkSpace_PointerReleased"> <Grid> <Image x:Name="cvWorkImage"/> <Canvas x:Name="cvWorkSpace"/> </Grid> </ScrollViewer> 在 PointerPressed 代码中,我捕获起点,在 PointerMoved 代码中,我在指针移动时绘制一个矩形(也删除我移动的尾随矩形,仅在画布中保留一个矩形。我使用以下方法实现矩形大小调整效果这个方法)。 PointerReleased 将接受最后一个矩形。 在支持触摸的设备中使用鼠标一切正常,但不使用手指。当我移动手指时图像就会滚动。 尝试将代码移至 Canvas 中,如下所示。无法同时使用鼠标和触摸绘制矩形。 <ScrollViewer x:Name="svWorkSpace" Visibility="Collapsed" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"> <Grid> <Image x:Name="cvWorkImage"/> <Canvas x:Name="cvWorkSpace" Tapped="svWorkSpace_Tapped" PointerPressed="svWorkSpace_PointerPressed" PointerMoved="svWorkSpace_PointerMoved" PointerReleased="svWorkSpace_PointerReleased"/> </Grid> </ScrollViewer> 请给我指出正确的方向。 当 ScrollViewer 接收到基于触摸的 PointerPressed 时,它会转向直接操作以响应地处理平移和缩放。直接操作捕获指针输入,因此 Canvas 的 PointerMoved 和 PointerReleased 事件不会触发。没有事件 -> 没有绘图。 ScrollViewer 使用鼠标平移或缩放,因此鼠标事件可以到达画布。 假设您总是希望 Canvas 处理指针事件而不是滚动(也许 Grid 中还有其他控件使用 ScrollViewer),您可以将 Canvas 的 ManipulationMone 设置为 all 以让 Canvas 块上的触摸触摸滚动查看器 <Canvas x:Name="cvWorkSpace" Background={ThemeResource WorkSpaceBackgroundBrush} Tapped="svWorkSpace_Tapped" ManipulationMode="All" PointerPressed="svWorkSpace_PointerPressed" PointerMoved="svWorkSpace_PointerMoved" PointerReleased="svWorkSpace_PointerReleased"/> 如果您只是有时希望 Canvas 处理指针事件,那么您可以将 ManipulationMode 切换回 System,让 ScrollViewer 处理它。如果您想通过单点触摸在画布上绘图并通过多点触摸平移/缩放,那么您可以处理画布上的操纵事件以平移和缩放。 还要确保画布不透明,并让指针事件传递到其后面的任何内容。如果你想在图像上绘图,你可以设置一个 ImageBrush,将图像作为 Canvas 的背景,而不是使用单独的 Image 控件。 10年前的一个答案现在对我有帮助。非常感谢。
可以在项目 UWP 中使用 NotifyIcon 类吗?
我在创建 xaml 控件时遇到问题。我正在 VS 2015 的通用应用程序中编写新项目。我想创建网格。在这个网格中我想要一个按钮。在模型中,我指定了列(级别)和 R...
如何确定 Windows 应用商店/通用应用程序中哪个 Dll 依赖项加载失败?
运行我正在处理的 UWP 项目时,我收到以下对话框。 “无法激活 Windows 应用商店应用程序‘MyAppsMangledName’。‘MyExeName’进程已启动,但激活请求失败...
如何在 Visual Studio 2022 中使用 Javascript + Html 制作 Windows 通用应用程序
我有一堆在 Visual Studio 2017 中制作的应用程序 - 我需要编辑其中一个,但不幸的是我无法找到安装 Visual Studio 2017 Community 的方法,所以我决定下一个最好的。 .
UWP 中使用什么,Binding 或 x:Bind,它们之间有什么区别? 因为我看到很多帖子中人们使用 Binding,而我只在 UWP 中使用 x:Bind 进行 Bind。 仅在 MSDN 主页上
我想检查 Windows 通用应用程序中的互联网连接类型。 未连接 通过无线局域网(WiFi)连接 通过 WWAN(蜂窝数据)连接 连接到按流量计费的网络 在或...
FilePicker PickSingleFileAsync() 调用上的 COMException^
我正在尝试制作一个游戏(通用DX11应用程序),在某些时候我需要访问图像库以允许用户选择头像。但由于某种原因,在选择器上调用 PickSingleFileAsync 会出现...
我想直接在我的xaml布局中访问资源,官方文档给了我们一些糟糕的例子,所以我无法让它工作。假设以下 Resources.resw : 我可以从...访问我的字符串资源
如何在 Microsoft Store API 中获取唯一的用户 ID
我使用 Microsoft Store API(以下简称“API”)来支持用户进行应用内购买(插件)。 例如... 公共 StoreContext storeContext = StoreContext.GetDefault(); GetAppLicenseAsync();
我的应用程序需要拍照,我从 uwp 示例中窃取了 MediaCapture 的大部分优点。但是,默认行为会创建分辨率非常低的照片 (640x480 => 52KB)。 我可以设置
自动增量无法与 Windows Phone 通用应用程序中的 sqlite-net 客户端一起使用
我在 Windows Phone 通用应用程序中使用 sqlite-net for sqlite 我有以下具有表和列属性的类,并使用异步连接在 sqlite 中添加数据,所有这些都正常工作...
使用 OnlineIdAuthenticator 在 Azure 应用服务中获取 NameIdentifier 声明
我正在使用 OnlineIdAuthenticator 类获取身份验证令牌以登录 Azure 应用服务,但我无法获取 NameIdentifier 声明服务器端。我需要唯一的 ID...
我目前正在尝试构建一个针对 Windows Phone 8.1、Windows 应用程序 8.1 和 Windows 10 通用应用程序的 Microsoft 运行时组件 C# 类库。为了完成这个介绍,我的环境...
我有一个播放音频文件的应用程序。当用户开始音频播放时,我希望音频在 300 毫秒或类似的时间内从有效的 0 音量淡入到 1。 我玩过...
无法在 Windows 10 UWP 中使用 HIDDevice 类打开 HID USB 设备
以下代码在某些Windows 10系统中返回null currentDevice = 等待 HidDevice.FromIdAsync(devices.ElementAt(0).Id, 文件访问模式.ReadWrite); 我发现了
轮询西门子徽标设备时出现System.IO.IOException
我是 Modbus 和 UWA 的新手,我正在尝试创建一个应用程序,从我的西门子徽标设备 (6ED1052-1HB08-0BA0 LOGO!24RCE) 读取输入 1、输出 1 和输出 2 的状态。标志是...
有没有办法在不安装的情况下启动通用Windows平台(UWP)应用程序? 我想从解压的 appx 文件夹启动 uwp 应用程序,但不知道如何启动。 据我所知,只有一种方法...
我有一个 UWP 应用程序,可以在两个不同的设备上使用。在最新的 Visual Studio 2019 更新后,我开始收到此错误: 未找到带有提供的指纹的证书:
我想在边框元素内部垂直写入文本。如图所示。 我尝试过使用 RenderTransform 与此代码 我想在边框元素内部垂直写入文本。如图所示。 我尝试使用 RenderTransform 与此代码 <Border Width="80" Background="Teal"> <TextBlock Text="CATEGORIES" Foreground="White" FontFamily="Segoe UI Black" FontSize="30"> <TextBlock.RenderTransform> <RotateTransform Angle="-90" /> </TextBlock.RenderTransform> </TextBlock> </Border> 这会垂直旋转文本,但 TextBlock 采用变换之前的旧高度和宽度值,并且不会完全显示文本。因此文本在 80 像素(边框元素的宽度)后被截断。在搜索时我发现使用 LayoutTransform 可以解决问题,但它在 UWP 应用程序中不可用。如何在 UWP XAML 中执行此操作? 这在 UWP 上也对我有用。只需使用here发布的类,而不是帖子中的类。并且还复制博客文章中的样式。 编辑:onedrive 链接不再有效。所以我在这里发布代码。 创建一个新类LayoutTransformer using System; using System.Diagnostics.CodeAnalysis; using Windows.Foundation; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Media; namespace Common { /// <summary> /// Represents a control that applies a layout transformation to its Content. /// </summary> /// <QualityBand>Preview</QualityBand> [TemplatePart(Name = TransformRootName, Type = typeof(Grid))] [TemplatePart(Name = PresenterName, Type = typeof(ContentPresenter))] public sealed class LayoutTransformer : ContentControl { /// <summary> /// Name of the TransformRoot template part. /// </summary> private const string TransformRootName = "TransformRoot"; /// <summary> /// Name of the Presenter template part. /// </summary> private const string PresenterName = "Presenter"; /// <summary> /// Gets or sets the layout transform to apply on the LayoutTransformer /// control content. /// </summary> /// <remarks> /// Corresponds to UIElement.LayoutTransform. /// </remarks> public Transform LayoutTransform { get { return (Transform)GetValue(LayoutTransformProperty); } set { SetValue(LayoutTransformProperty, value); } } /// <summary> /// Identifies the LayoutTransform DependencyProperty. /// </summary> public static readonly DependencyProperty LayoutTransformProperty = DependencyProperty.Register( "LayoutTransform", typeof(Transform), typeof(LayoutTransformer), new PropertyMetadata(null, LayoutTransformChanged)); /// <summary> /// Gets the child element being transformed. /// </summary> private FrameworkElement Child { get { // Preferred child is the content; fall back to the presenter itself return (null != _contentPresenter) ? (_contentPresenter.Content as FrameworkElement ?? _contentPresenter) : null; } } // Note: AcceptableDelta and DecimalsAfterRound work around double arithmetic rounding issues on Silverlight. private const double AcceptableDelta = 0.0001; private const int DecimalsAfterRound = 4; private Panel _transformRoot; private ContentPresenter _contentPresenter; private MatrixTransform _matrixTransform; private Matrix _transformation; private Size _childActualSize = Size.Empty; public LayoutTransformer() { // Associated default style DefaultStyleKey = typeof(LayoutTransformer); // Can't tab to LayoutTransformer IsTabStop = false; #if SILVERLIGHT // Disable layout rounding because its rounding of values confuses things UseLayoutRounding = false; #endif } /// <summary> /// Builds the visual tree for the LayoutTransformer control when a new /// template is applied. /// </summary> protected override void OnApplyTemplate() { // Apply new template base.OnApplyTemplate(); // Find template parts _transformRoot = GetTemplateChild(TransformRootName) as Grid; _contentPresenter = GetTemplateChild(PresenterName) as ContentPresenter; _matrixTransform = new MatrixTransform(); if (null != _transformRoot) { _transformRoot.RenderTransform = _matrixTransform; } // Apply the current transform ApplyLayoutTransform(); } /// <summary> /// Handles changes to the Transform DependencyProperty. /// </summary> /// <param name="o">Source of the change.</param> /// <param name="e">Event args.</param> private static void LayoutTransformChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) { // Casts are safe because Silverlight is enforcing the types ((LayoutTransformer)o).ProcessTransform((Transform)e.NewValue); } /// <summary> /// Applies the layout transform on the LayoutTransformer control content. /// </summary> /// <remarks> /// Only used in advanced scenarios (like animating the LayoutTransform). /// Should be used to notify the LayoutTransformer control that some aspect /// of its Transform property has changed. /// </remarks> public void ApplyLayoutTransform() { ProcessTransform(LayoutTransform); } /// <summary> /// Processes the Transform to determine the corresponding Matrix. /// </summary> /// <param name="transform">Transform to process.</param> private void ProcessTransform(Transform transform) { // Get the transform matrix and apply it _transformation = RoundMatrix(GetTransformMatrix(transform), DecimalsAfterRound); if (null != _matrixTransform) { _matrixTransform.Matrix = _transformation; } // New transform means re-layout is necessary InvalidateMeasure(); } /// <summary> /// Walks the Transform(Group) and returns the corresponding Matrix. /// </summary> /// <param name="transform">Transform(Group) to walk.</param> /// <returns>Computed Matrix.</returns> private Matrix GetTransformMatrix(Transform transform) { if (null != transform) { // WPF equivalent of this entire method: // return transform.Value; // Process the TransformGroup TransformGroup transformGroup = transform as TransformGroup; if (null != transformGroup) { Matrix groupMatrix = Matrix.Identity; foreach (Transform child in transformGroup.Children) { groupMatrix = MatrixMultiply(groupMatrix, GetTransformMatrix(child)); } return groupMatrix; } // Process the RotateTransform RotateTransform rotateTransform = transform as RotateTransform; if (null != rotateTransform) { double angle = rotateTransform.Angle; double angleRadians = (2 * Math.PI * angle) / 360; double sine = Math.Sin(angleRadians); double cosine = Math.Cos(angleRadians); return new Matrix(cosine, sine, -sine, cosine, 0, 0); } // Process the ScaleTransform ScaleTransform scaleTransform = transform as ScaleTransform; if (null != scaleTransform) { double scaleX = scaleTransform.ScaleX; double scaleY = scaleTransform.ScaleY; return new Matrix(scaleX, 0, 0, scaleY, 0, 0); } // Process the SkewTransform SkewTransform skewTransform = transform as SkewTransform; if (null != skewTransform) { double angleX = skewTransform.AngleX; double angleY = skewTransform.AngleY; double angleXRadians = (2 * Math.PI * angleX) / 360; double angleYRadians = (2 * Math.PI * angleY) / 360; return new Matrix(1, angleYRadians, angleXRadians, 1, 0, 0); } // Process the MatrixTransform MatrixTransform matrixTransform = transform as MatrixTransform; if (null != matrixTransform) { return matrixTransform.Matrix; } // TranslateTransform has no effect in LayoutTransform } // Fall back to no-op transformation return Matrix.Identity; } /// <summary> /// Provides the behavior for the "Measure" pass of layout. /// </summary> /// <param name="availableSize">The available size that this element can give to child elements.</param> /// <returns>The size that this element determines it needs during layout, based on its calculations of child element sizes.</returns> protected override Size MeasureOverride(Size availableSize) { FrameworkElement child = Child; if ((null == _transformRoot) || (null == child)) { // No content, no size return Size.Empty; } //DiagnosticWriteLine("MeasureOverride < " + availableSize); Size measureSize; if (_childActualSize == Size.Empty) { // Determine the largest size after the transformation measureSize = ComputeLargestTransformedSize(availableSize); } else { // Previous measure/arrange pass determined that Child.DesiredSize was larger than believed //DiagnosticWriteLine(" Using _childActualSize"); measureSize = _childActualSize; } // Perform a mesaure on the _transformRoot (containing Child) //DiagnosticWriteLine(" _transformRoot.Measure < " + measureSize); _transformRoot.Measure(measureSize); //DiagnosticWriteLine(" _transformRoot.DesiredSize = " + _transformRoot.DesiredSize); // WPF equivalent of _childActualSize technique (much simpler, but doesn't work on Silverlight 2) // // If the child is going to render larger than the available size, re-measure according to that size // child.Arrange(new Rect()); // if (child.RenderSize != child.DesiredSize) // { // _transformRoot.Measure(child.RenderSize); // } // Transform DesiredSize to find its width/height Rect transformedDesiredRect = RectTransform(new Rect(0, 0, _transformRoot.DesiredSize.Width, _transformRoot.DesiredSize.Height), _transformation); Size transformedDesiredSize = new Size(transformedDesiredRect.Width, transformedDesiredRect.Height); // Return result to allocate enough space for the transformation //DiagnosticWriteLine("MeasureOverride > " + transformedDesiredSize); return transformedDesiredSize; } /// <summary> /// Provides the behavior for the "Arrange" pass of layout. /// </summary> /// <param name="finalSize">The final area within the parent that this element should use to arrange itself and its children.</param> /// <returns>The actual size used.</returns> /// <remarks> /// Using the WPF paramater name finalSize instead of Silverlight's finalSize for clarity /// </remarks> protected override Size ArrangeOverride(Size finalSize) { FrameworkElement child = Child; if ((null == _transformRoot) || (null == child)) { // No child, use whatever was given return finalSize; } //DiagnosticWriteLine("ArrangeOverride < " + finalSize); // Determine the largest available size after the transformation Size finalSizeTransformed = ComputeLargestTransformedSize(finalSize); if (IsSizeSmaller(finalSizeTransformed, _transformRoot.DesiredSize)) { // Some elements do not like being given less space than they asked for (ex: TextBlock) // Bump the working size up to do the right thing by them //DiagnosticWriteLine(" Replacing finalSizeTransformed with larger _transformRoot.DesiredSize"); finalSizeTransformed = _transformRoot.DesiredSize; } //DiagnosticWriteLine(" finalSizeTransformed = " + finalSizeTransformed); // Transform the working size to find its width/height Rect transformedRect = RectTransform(new Rect(0, 0, finalSizeTransformed.Width, finalSizeTransformed.Height), _transformation); // Create the Arrange rect to center the transformed content Rect finalRect = new Rect( -transformedRect.Left + ((finalSize.Width - transformedRect.Width) / 2), -transformedRect.Top + ((finalSize.Height - transformedRect.Height) / 2), finalSizeTransformed.Width, finalSizeTransformed.Height); // Perform an Arrange on _transformRoot (containing Child) //DiagnosticWriteLine(" _transformRoot.Arrange < " + finalRect); _transformRoot.Arrange(finalRect); //DiagnosticWriteLine(" Child.RenderSize = " + child.RenderSize); // This is the first opportunity under Silverlight to find out the Child's true DesiredSize if (IsSizeSmaller(finalSizeTransformed, child.RenderSize) && (Size.Empty == _childActualSize)) { // Unfortunately, all the work so far is invalid because the wrong DesiredSize was used //DiagnosticWriteLine(" finalSizeTransformed smaller than Child.RenderSize"); // Make a note of the actual DesiredSize _childActualSize = new Size(child.ActualWidth, child.ActualHeight); //DiagnosticWriteLine(" _childActualSize = " + _childActualSize); // Force a new measure/arrange pass InvalidateMeasure(); } else { // Clear the "need to measure/arrange again" flag _childActualSize = Size.Empty; } //DiagnosticWriteLine(" _transformRoot.RenderSize = " + _transformRoot.RenderSize); // Return result to perform the transformation //DiagnosticWriteLine("ArrangeOverride > " + finalSize); return finalSize; } /// <summary> /// Compute the largest usable size (greatest area) after applying the transformation to the specified bounds. /// </summary> /// <param name="arrangeBounds">Arrange bounds.</param> /// <returns>Largest Size possible.</returns> [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Closely corresponds to WPF's FrameworkElement.FindMaximalAreaLocalSpaceRect.")] private Size ComputeLargestTransformedSize(Size arrangeBounds) { //DiagnosticWriteLine(" ComputeLargestTransformedSize < " + arrangeBounds); // Computed largest transformed size Size computedSize = Size.Empty; // Detect infinite bounds and constrain the scenario bool infiniteWidth = double.IsInfinity(arrangeBounds.Width); if (infiniteWidth) { arrangeBounds.Width = arrangeBounds.Height; } bool infiniteHeight = double.IsInfinity(arrangeBounds.Height); if (infiniteHeight) { arrangeBounds.Height = arrangeBounds.Width; } // Capture the matrix parameters double a = _transformation.M11; double b = _transformation.M12; double c = _transformation.M21; double d = _transformation.M22; // Compute maximum possible transformed width/height based on starting width/height // These constraints define two lines in the positive x/y quadrant double maxWidthFromWidth = Math.Abs(arrangeBounds.Width / a); double maxHeightFromWidth = Math.Abs(arrangeBounds.Width / c); double maxWidthFromHeight = Math.Abs(arrangeBounds.Height / b); double maxHeightFromHeight = Math.Abs(arrangeBounds.Height / d); // The transformed width/height that maximize the area under each segment is its midpoint // At most one of the two midpoints will satisfy both constraints double idealWidthFromWidth = maxWidthFromWidth / 2; double idealHeightFromWidth = maxHeightFromWidth / 2; double idealWidthFromHeight = maxWidthFromHeight / 2; double idealHeightFromHeight = maxHeightFromHeight / 2; // Compute slope of both constraint lines double slopeFromWidth = -(maxHeightFromWidth / maxWidthFromWidth); double slopeFromHeight = -(maxHeightFromHeight / maxWidthFromHeight); if ((0 == arrangeBounds.Width) || (0 == arrangeBounds.Height)) { // Check for empty bounds computedSize = new Size(arrangeBounds.Width, arrangeBounds.Height); } else if (infiniteWidth && infiniteHeight) { // Check for completely unbound scenario computedSize = new Size(double.PositiveInfinity, double.PositiveInfinity); } else if (!MatrixHasInverse(_transformation)) { // Check for singular matrix computedSize = new Size(0, 0); } else if ((0 == b) || (0 == c)) { // Check for 0/180 degree special cases double maxHeight = (infiniteHeight ? double.PositiveInfinity : maxHeightFromHeight); double maxWidth = (infiniteWidth ? double.PositiveInfinity : maxWidthFromWidth); if ((0 == b) && (0 == c)) { // No constraints computedSize = new Size(maxWidth, maxHeight); } else if (0 == b) { // Constrained by width double computedHeight = Math.Min(idealHeightFromWidth, maxHeight); computedSize = new Size( maxWidth - Math.Abs((c * computedHeight) / a), computedHeight); } else if (0 == c) { // Constrained by height double computedWidth = Math.Min(idealWidthFromHeight, maxWidth); computedSize = new Size( computedWidth, maxHeight - Math.Abs((b * computedWidth) / d)); } } else if ((0 == a) || (0 == d)) { // Check for 90/270 degree special cases double maxWidth = (infiniteHeight ? double.PositiveInfinity : maxWidthFromHeight); double maxHeight = (infiniteWidth ? double.PositiveInfinity : maxHeightFromWidth); if ((0 == a) && (0 == d)) { // No constraints computedSize = new Size(maxWidth, maxHeight); } else if (0 == a) { // Constrained by width double computedHeight = Math.Min(idealHeightFromHeight, maxHeight); computedSize = new Size( maxWidth - Math.Abs((d * computedHeight) / b), computedHeight); } else if (0 == d) { // Constrained by height double computedWidth = Math.Min(idealWidthFromWidth, maxWidth); computedSize = new Size( computedWidth, maxHeight - Math.Abs((a * computedWidth) / c)); } } else if (idealHeightFromWidth <= ((slopeFromHeight * idealWidthFromWidth) + maxHeightFromHeight)) { // Check the width midpoint for viability (by being below the height constraint line) computedSize = new Size(idealWidthFromWidth, idealHeightFromWidth); } else if (idealHeightFromHeight <= ((slopeFromWidth * idealWidthFromHeight) + maxHeightFromWidth)) { // Check the height midpoint for viability (by being below the width constraint line) computedSize = new Size(idealWidthFromHeight, idealHeightFromHeight); } else { // Neither midpoint is viable; use the intersection of the two constraint lines instead // Compute width by setting heights equal (m1*x+c1=m2*x+c2) double computedWidth = (maxHeightFromHeight - maxHeightFromWidth) / (slopeFromWidth - slopeFromHeight); // Compute height from width constraint line (y=m*x+c; using height would give same result) computedSize = new Size( computedWidth, (slopeFromWidth * computedWidth) + maxHeightFromWidth); } // Return result //DiagnosticWriteLine(" ComputeLargestTransformedSize > " + computedSize); return computedSize; } /// <summary> /// Returns true if Size a is smaller than Size b in either dimension. /// </summary> /// <param name="a">Second Size.</param> /// <param name="b">First Size.</param> /// <returns>True if Size a is smaller than Size b in either dimension.</returns> private static bool IsSizeSmaller(Size a, Size b) { // WPF equivalent of following code: // return ((a.Width < b.Width) || (a.Height < b.Height)); return ((a.Width + AcceptableDelta < b.Width) || (a.Height + AcceptableDelta < b.Height)); } /// <summary> /// Rounds the non-offset elements of a Matrix to avoid issues due to floating point imprecision. /// </summary> /// <param name="matrix">Matrix to round.</param> /// <param name="decimals">Number of decimal places to round to.</param> /// <returns>Rounded Matrix.</returns> private static Matrix RoundMatrix(Matrix matrix, int decimals) { return new Matrix( Math.Round(matrix.M11, decimals), Math.Round(matrix.M12, decimals), Math.Round(matrix.M21, decimals), Math.Round(matrix.M22, decimals), matrix.OffsetX, matrix.OffsetY); } /// <summary> /// Implements WPF's Rect.Transform on Silverlight. /// </summary> /// <param name="rect">Rect to transform.</param> /// <param name="matrix">Matrix to transform with.</param> /// <returns>Bounding box of transformed Rect.</returns> private static Rect RectTransform(Rect rect, Matrix matrix) { // WPF equivalent of following code: // Rect rectTransformed = Rect.Transform(rect, matrix); Point leftTop = matrix.Transform(new Point(rect.Left, rect.Top)); Point rightTop = matrix.Transform(new Point(rect.Right, rect.Top)); Point leftBottom = matrix.Transform(new Point(rect.Left, rect.Bottom)); Point rightBottom = matrix.Transform(new Point(rect.Right, rect.Bottom)); double left = Math.Min(Math.Min(leftTop.X, rightTop.X), Math.Min(leftBottom.X, rightBottom.X)); double top = Math.Min(Math.Min(leftTop.Y, rightTop.Y), Math.Min(leftBottom.Y, rightBottom.Y)); double right = Math.Max(Math.Max(leftTop.X, rightTop.X), Math.Max(leftBottom.X, rightBottom.X)); double bottom = Math.Max(Math.Max(leftTop.Y, rightTop.Y), Math.Max(leftBottom.Y, rightBottom.Y)); Rect rectTransformed = new Rect(left, top, right - left, bottom - top); return rectTransformed; } /// <summary> /// Implements WPF's Matrix.Multiply on Silverlight. /// </summary> /// <param name="matrix1">First matrix.</param> /// <param name="matrix2">Second matrix.</param> /// <returns>Multiplication result.</returns> private static Matrix MatrixMultiply(Matrix matrix1, Matrix matrix2) { // WPF equivalent of following code: // return Matrix.Multiply(matrix1, matrix2); return new Matrix( (matrix1.M11 * matrix2.M11) + (matrix1.M12 * matrix2.M21), (matrix1.M11 * matrix2.M12) + (matrix1.M12 * matrix2.M22), (matrix1.M21 * matrix2.M11) + (matrix1.M22 * matrix2.M21), (matrix1.M21 * matrix2.M12) + (matrix1.M22 * matrix2.M22), ((matrix1.OffsetX * matrix2.M11) + (matrix1.OffsetY * matrix2.M21)) + matrix2.OffsetX, ((matrix1.OffsetX * matrix2.M12) + (matrix1.OffsetY * matrix2.M22)) + matrix2.OffsetY); } /// <summary> /// Implements WPF's Matrix.HasInverse on Silverlight. /// </summary> /// <param name="matrix">Matrix to check for inverse.</param> /// <returns>True if the Matrix has an inverse.</returns> private static bool MatrixHasInverse(Matrix matrix) { // WPF equivalent of following code: // return matrix.HasInverse; return (0 != ((matrix.M11 * matrix.M22) - (matrix.M12 * matrix.M21))); } } } 在 App.xaml 文件中 添加通用命名空间 xmlns:common="using:Common" 在 ApplicationResources 中创建新样式 <Application.Resources> <Style TargetType="common:LayoutTransformer"> <Setter Property="Foreground" Value="#FF000000"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="common:LayoutTransformer"> <Grid x:Name="TransformRoot" Background="{TemplateBinding Background}"> <ContentPresenter x:Name="Presenter" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}"/> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </Application.Resources> 现在将文本块逆时针旋转 90 度 添加通用命名空间 xmlns:common="using:Common" 并使用此代码 <common:LayoutTransformer> <common:LayoutTransformer.LayoutTransform> <RotateTransform Angle="-90" /> </common:LayoutTransformer.LayoutTransform> <TextBlock Text="CATEGORIES" FontSize="30"/> </common:LayoutTransformer> 如果旋转边框(父边框),TextBlock 也会旋转,因为它是边框的子边框。 <Border Height="80" Background="Teal"> <Border.RenderTransform> <RotateTransform Angle="-90" /> </Border.RenderTransform> <TextBlock Text="CATEGORIES" Foreground="White" FontFamily="Segoe UI Black" FontSize="30"> </TextBlock> </Border>