我想劫持通常的WPF渲染,将控件拆分为基元,进行布局管理,为我应用绑定等.
据我所知,WPF中的整个渲染归结为在布局管理器使用依赖属性系统定义的值计算的位置处渲染基元(文本,图像,线,曲线).如果我可以提供自己的原始渲染逻辑,我将能够渲染到例如自定义文档类型,传输基元以通过网络进行实际渲染等.
我的计划如下:
DrawingContext.该DrawingContext是一个抽象类,它定义了一堆类似的方法DrawEllipse,DrawText,DrawImage等等-我需要提供自己的实现此功能.UserControl并强制它呈现给定的DrawingContext.但是我遇到了以下问题:
DrawingContext包含抽象的内部方法void PushGuidelineY1(double coordinate)和void PushGuidelineY2(double leadingCoordinate, double offsetToDrivenCoordinate),我不能轻易忽略.(也许有一些技巧可以解决这个问题?)DrawingContext?为什么?我可以做点什么
void RenderRecursively(UIElement e, DrawingContext ctx)
{
e.OnRender(ctx);
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(e); i++)
RenderRecursively((UIElement)VisualTreeHelper.GetChild(e, i), ctx);
}
Run Code Online (Sandbox Code Playgroud)
- 但我想知道是否有直接的渲染方法UIElement.(当然,这个问题很小,但看不到它的基础设施让我想知道这是不是正确的方法.)
那么,DrawingContext不打算继承吗?为定制提供DrawingContext正确方向的整个想法,还是我需要重新考虑策略?是否正在绘制WPF支持的自定义上下文,或者我需要寻找不同的拦截点?
我有一个DrawingContext(Visual或DrawingGroup的一部分),我在其中绘制一堆矩形和/或1位图像.可以将其视为屏蔽1位图像.我想将其转换为位图图像文件.
使用RenderTargetBitmap不是一个选项,因为它只能以32位像素格式渲染,所以如果我必须渲染一个20MB的1位图像,我的堆上最终会得到640MB(20*32)的内存.这当然会产生宏伟的LOH碎片,并且应用程序在第二次拍摄时会耗尽内存.
所以,我基本上需要一种方法来有效地从绘图上下文中写入1位位图文件.任何想法/建议/替代方法将不胜感激.
我正在绘制一个DrawingContext,我想对绘图的一部分应用阴影效果.目前我在a中创建相关部分DrawingGroup并应用a BitmapEffect,但这没有效果:
var layer = new DrawingGroup();
using (var lcontext = layer.Open())
{
// draw stuff in lcontext
}
layer.BitmapEffect = new DropShadowBitmapEffect { Color = Colors.Black, ShadowDepth = 3, Opacity = 0.5 };
context.DrawDrawing(layer);
Run Code Online (Sandbox Code Playgroud)
这将layer正确地绘制所有内容,但没有投影效果.
我做错了什么/如何在DrawingContext中对一堆基元应用投影?
目前我在画布上有一个图像,我可以在我的应用程序中自由移动,我有6层DrawingVisuals渲染,但它似乎很慢.我正在使用RenderTargetBitmap来渲染视觉效果.是否有更快的方式在图像或任何其他框架元素上显示视觉效果,我可以在画布上自由移动?
XAML:
<Canvas>
<Image Height="505" HorizontalAlignment="Left" Margin="0,0,0,0" Name="_MapImage" Stretch="Fill" VerticalAlignment="Top" Width="700" MouseLeftButtonDown="_MapImage_MouseDown" MouseWheel="_MapImage_MouseWheel" MouseLeftButtonUp="_MapImage_MouseUp" MouseMove="_MapImage_MouseMove" />
</Canvas>
Run Code Online (Sandbox Code Playgroud)
码:
_renderRoutesBitmap = new RenderTargetBitmap((int)(_MapImage.Width), (int)(_MapImage.Height), 96, 96, PixelFormats.Default);
for (int i = 6; i < 8; ++i)
{
if((layerCode / (int)Math.Pow(10,i) % 2) == 1)
_renderRoutesBitmap.Render(_layers[i]); //takes too much time
}
_RouteImage.Source = _renderRoutesBitmap;
Run Code Online (Sandbox Code Playgroud) 我正在WPF中构建一个自定义UI框架,在这里我基本上放弃了尽可能多的内置布局系统和控件。到目前为止,我一直没有UIElement直接涉足,但是由于我已经在进行测量,整理和渲染自己,所以我认为我可以通过甚至“更接近金属”来减少WPF的更多遗产(尤其是当它来的时候)进行布局/渲染)。在保持托管代码的同时又不害怕自己做肮脏的工作的情况下,有多接近?
我现在正在一边玩一个原型概念,在这个概念中,我只有一个元素继承自UIElement:一个Root类似于剥离的对象Canvas,它“托管”了我的其余布局引擎,并将相关的IInputElement利益引入其中。从那时起,所有元素将完全是自定义对象,而不是从WPF中的任何内容继承而来,而是直接呈现到DrawingContextRoot中(在其OnRender方法中)。
现在,我想知道拥有WriteableBitmap根元素并手动使用它的相对性能,例如,为了方便起见,使用WriteableBitmapEx。没有抗锯齿不是问题,定制命中测试系统也不是问题。
我的想法主要是WriteableBitmap(Ex)不具有任何GPU加速增益的特权,因此,当需要重绘/变换大面积区域时,WriteableBitmap(Ex)的速度将大大降低。
但是,对于“基于像素的渲染引擎”,我确实还有其他需求,因此我仍然对此感兴趣。
有什么见解吗?
编辑:在这种情况下,SharpDX呢?也许曾经的我在这我还不如去与一个DirectX包装像SharpDX一个WinForms的解决方案(..或..我想我真正应该做的是注册了整个C ++安吉拉卷,但不幸的是我没有有时间开始学习这些东西。..
NSStringDrawingContext的actualScaleFactor何时更改?
"如果在minimumScaleFactor属性中指定了自定义值,则在绘制完成时,此属性包含用于绘制字符串的实际比例因子值."
我的代码:
myButton.titleLabel!.font = UIFont(name: "AmericanTypewriter-Bold", size: 40)
myButton.titleLabel?.adjustsFontSizeToFitWidth = true
myButton.setTitle("\(textString)", forState: .Normal)
let attributes = [NSFontAttributeName : myButton.titleLabel!.font]
let attributedString = NSMutableAttributedString(string:textString, attributes:attributes)
let context = NSStringDrawingContext()
context.minimumScaleFactor = myButton.titleLabel!.minimumScaleFactor
print("context: \(context.actualScaleFactor)")
let resultingRect = attributedString.boundingRectWithSize(myButton.titleLabel!.bounds.size, options: .UsesLineFragmentOrigin, context: context)
print("actual context after drawing: \(context.actualScaleFactor)")
//want to get the font size after adjustsFontSizeToFitWidth has done its magic:
//let actualFontSize = myButton.titleLabel!.font.pointSize * context.actualScaleFactor
Run Code Online (Sandbox Code Playgroud)
适合不缩小的文本的控制台日志和调整为适合标签宽度的较长文本都是相同的:
context: 0.0
actual context after drawing: 1.0
Run Code Online (Sandbox Code Playgroud)
知道在文本大小适合标签后,从上下文中获取真正的scaleFactor的步骤是什么?
当我画这样的东西时(这里只是随机图纸):
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DrawingVisual visual = new DrawingVisual();
DrawingContext context = visual.RenderOpen();
Pen pen = new Pen(Brushes.Black, 1);
context.DrawEllipse(Brushes.YellowGreen, pen, new Point(0,0), 40, 40);
for (int i = 0; i <= 100 - 1; i++)
context.DrawLine(new Pen(Brushes.Black, 1), new Point(0, i), new Point(i, i));
context.Close();
RenderTargetBitmap bmp = new RenderTargetBitmap(100, 100, 96, 96, PixelFormats.Pbgra32);
bmp.Render(visual);
image1.Source = bmp;
}
}
Run Code Online (Sandbox Code Playgroud)
DrawLine和DrawEllipse混合的颜色.(我发现只有DrawLine才使用笔,而不是像Rectangle和Ellipse这样使用Brush的其他形式).奇怪的是,即使是基础网格背景(argh)的LinearGradientBrush的颜色. 我希望它们是z-Ordered,每个都具有完全不透明度.
这里是XAML代码:
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"> …Run Code Online (Sandbox Code Playgroud) 这是我的第一个问题,但是我是一个很长时间的潜伏者.我将其分为两部分,一部分解释我正在做什么以及为什么我认为这是要走的路,第二部分是我无法为自己解决的实际问题.
我在做什么? 我目前正在开发一个用于渲染二维特征的框架,以便实时显示.您可以在浏览器中考虑Google地图等应用程序,但该框架旨在呈现各种地理数据(而不仅仅是轴对齐的栅格数据,如Google Tiles).
该框架将集成到我们(公司)的最新产品中,该产品是用于台式机和笔记本电脑的WPF应用程序.
因此,我选择了WPF的实际渲染几何只 ; 可见性和遮挡剔除由我自己完成,输入处理(鼠标拾取),移动相机等.
作为实时应用程序,它需要至少达到30 FPS.渲染图像时框架表现得足够:我可以每帧绘制几千个位图而不会出现问题,但多边形数据却成为一个主要问题.
我正在使用WPF渲染相当数量的折线和多边形数据的实际问题,特别是使用DrawingContext和StreamGeometry.到目前为止,我的理解是,如果我需要表现,这就是我要采取的方法.但是,我无法达到我期望的结果.
这就是我用实际数据填充StreamGeometry的方法:
using (StreamGeometryContext ctx = Geometry.Open())
{
foreach (var segment in segments)
{
var first = ToWpf(segment[0]);
ctx.BeginFigure(first, false, false);
// Skip the first point, obviously
List<Point> points = segment.Skip(1).Select(ToWpf).ToList();
ctx.PolyLineTo(points, true, false);
}
}
Geometry.Freeze();
Run Code Online (Sandbox Code Playgroud)
这就是我绘制几何体的方式:
_dc.PushTransform(_mercatorToView);
_dc.DrawGeometry(null, _pen, polyline);
_dc.Pop();
Run Code Online (Sandbox Code Playgroud)
作为测试,我将OpenStreetMap中的ESRI形状加载到我的应用程序中以测试其性能,但我完全不满意:我的测试数据包含~3500个线段,总共约20k行.
将每个段映射到它自己的StreamGeometry表现得非常糟糕,但我已经预料到了:渲染大约需要14秒.
然后我尝试使用多个数字将更多段包装到相同的StreamGeometry中:80 StreamGeometry,渲染大约需要50ms.
但是我得不到比这更好的结果.将行数增加到大约100k使我的应用程序几乎无法使用:渲染需要超过100毫秒. 除了在渲染矢量数据时同时冻结几何体和笔,我还能做些什么呢?
我现在更喜欢使用DirectX而不是依赖WPF来做它,因为某些东西似乎非常错误.
编辑
为了进一步阐明我在做什么:该应用程序实时显示地理数据,非常像浏览器中的谷歌地图等应用程序:但它应该可视化更多,更多的数据.您可能知道,谷歌地图允许缩放和平移,它需要> 25 FPS才能显示为流畅的动画; 任何不足都不会流利.
*对不起,我不应该在实际产品发布之前上传这个视频.然而,您可以设想像谷歌地图这样的东西,但是有大量的矢量数据(多边形和折线).*
有两种解决方案,其中一种经常被陈述:
在位图中缓存重图
实现看起来有点简单,但我发现这种方法存在一些问题:为了正确实现平移,我需要避免 …
我将实时绘制数百条线。我选择了视觉层来做到这一点。但我看到这里有两种不同的画线方式。您建议使用哪一种以获得更好的性能和速度?
1.DrawingContext.DrawLine
public class DrawingTypeOne : FrameworkElement
{
private readonly VisualCollection _visuals;
public DrawingTypeOne(double thickness)
{
var myPen = new Pen
{
Thickness = 1,
Brush = Brushes.White,
};
myPen.Freeze();
_visuals = new VisualCollection(this);
var drawingVisual = new DrawingVisual();
using (var dc = drawingVisual.RenderOpen())
{
dc.DrawLine(myPen, new Point(0,0) , new Point(100,100));
_visuals.Add(drawingVisual);
}
}
protected override Visual GetVisualChild(int index)
{
return _visuals[index];
}
protected override int VisualChildrenCount
{
get
{
return _visuals.Count;
}
}
}
Run Code Online (Sandbox Code Playgroud)
2. …
使用DrawingContext该类我已经能够使用该DrawRectangle()方法成功地将adorner添加到我的adornedElement.
是否可以构建一个堆栈面板,内部有文本框和图像 - 并将其指定为装饰器?
我顺便使用visual studio 2010 - 而不是微软表达.
非常感谢,
担