我有一个复杂的用户控件,它显示一个图像并用阴影和东西覆盖它上面的某些标签.我想在内存中渲染所有这些内容,然后制作此地图的图像,然后在真实用户界面中使用此图像.这就是事情的结局.
我这样做是因为界面开始慢慢移动所有这些元素,我正在尝试简化它.我会走正确的路吗?
这里的问题是我创建了brainMap,用数据提供它,然后尝试创建imagen和BAM!它无法完成,因为整个组件未呈现,ActualWith为零.
这就是我从控件中提取图像的方法(当控件在屏幕中呈现时,该方法非常有效)
/// <summary> /// The controls need actual size,If they are not render an "UpdateLayout()" might be needed. /// </summary> /// <param name="control"></param> /// <param name="Container"></param> public static System.Windows.Controls.Image fromControlToImage(System.Windows.FrameworkElement control) { if (control.ActualWidth == 0) throw new Exception("The control has no size,UpdateLayout is needed"); // Here is where I get fired if the control was not actually rendered in the screen RenderTargetBitmap rtb = new RenderTargetBitmap((int)control.ActualWidth,(int)control.ActualHeight,96,PixelFormats.Pbgra32); rtb.Render(control); var bitmapImage = new BitmapImage(); var bitmapEncoder = new PngBitmapEncoder(); bitmapEncoder.Frames.Add(BitmapFrame.Create(rtb)); using (var stream = new System.IO.MemoryStream()) { bitmapEncoder.Save(stream); stream.Seek(0,System.IO.SeekOrigin.Begin); bitmapImage.BeginInit(); bitmapImage.CacheOption = BitmapCacheOption.OnLoad; bitmapImage.StreamSource = stream; bitmapImage.EndInit(); } System.Windows.Controls.Image testImage = new System.Windows.Controls.Image(); testImage.Source = bitmapImage; return testImage; }
如果控件是开头布局的一部分,添加UpdateLayout确实解决了问题(这就是为什么我为自己添加了一个例外),但是当从代码创建控件并且从未到达页面时,UpdateLayout根本无法帮助.
我该怎么做才能确保渲染内存中的所有元素,然后在不进入页面的情况下渲染它的图像? (固定尺寸可以选择)
解决方法
在您的情况下,解决方案将是这样的:
public static System.Windows.Controls.Image fromControlToImage(System.Windows.FrameworkElement control) { Size size = new Size(100,100); // Or what ever size you want... control.Measure(size); control.Arrange(new Rect(size)); control.UpdateLayout(); ... }
在SO中通常会询问内存中的WPF:
As the control has no parent container,you need to call Measure and Arrange in order to do a proper layout.
WPF Get Size of UIElement in Memory
You need to force a render of the item,or wait for the item to be rendered. You can then use the ActualHeight and ActualWidth properties.
为您的目的另外一个:
Force Rendering of a WPF Control in Memory
Propably you can use a ViewBox to render in memory