【问题标题】:Saving FrameworkElement with its DataContext to image file does no succeed将 FrameworkElement 及其 DataContext 保存到图像文件没有成功
【发布时间】:2012-12-27 16:22:13
【问题描述】:

我有一个名为 UserControl1 的简单用户控件,其中包含一个 TextBlock:

  <UserControl x:Class="WpfApplication2.UserControl1"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
     <Grid>
         <TextBlock Text="{Binding}"/>
     </Grid>
</UserControl>

我初始化了它的一个新实例,并在代码中给它一个 DataContext。当窗口关闭时,我必须将此控件绘制到图像文件中。 UserControl 不会在已创建的文件中呈现有界文本。

这是我使用用户控件的代码:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        Closing += MainWindow_Closing;
    }

    void MainWindow_Closing(object sender, CancelEventArgs e)
    {
        UserControl1 uc = new UserControl1();
        uc.DataContext = "hello";
        uc.Height = 100;
        uc.Width = 100;
        uc.Background = Brushes.LightBlue;
        DrawToImage(uc);
    }

    private void DrawToImage(FrameworkElement element)
    {
        element.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
        element.Arrange(new Rect(element.DesiredSize));

        RenderTargetBitmap bitmap = new RenderTargetBitmap((int)element.Width, (int)element.Height,
                                                           120.0, 120.0, PixelFormats.Pbgra32);
        bitmap.Render(element);

        BitmapEncoder encoder = new PngBitmapEncoder();
        encoder.Frames.Add(BitmapFrame.Create(bitmap));

        using (Stream s = File.OpenWrite(@"C:\555.png"))
        {
            encoder.Save(s);
        }
    }
}

我希望它足够清楚,任何帮助将不胜感激。

【问题讨论】:

  • 如果我将用户控件放在窗口中它可以正常工作,你能做到吗?

标签: wpf render datacontext


【解决方案1】:

您只是在手动测量/排列控件后忘记强制对控件进行布局更新(这不足以强制解决绑定问题)。

UpdateLayout 的简单调用使其工作:

private void DrawToImage(FrameworkElement element)
{
    element.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
    element.Arrange(new Rect(element.DesiredSize));
    element.UpdateLayout();

    RenderTargetBitmap bitmap = new RenderTargetBitmap((int)element.Width, (int)element.Height,
                                                        120.0, 120.0, PixelFormats.Pbgra32);
    bitmap.Render(element);

    BitmapEncoder encoder = new PngBitmapEncoder();
    encoder.Frames.Add(BitmapFrame.Create(bitmap));

    using (Stream s = File.OpenWrite(@"C:\555.png"))
    {
        encoder.Save(s);
    }
}

编辑:更多关于何时解决绑定:link

【讨论】:

  • 很好的答案,我是 WPF 新手,能否请您提供有用教程的链接,我必须主要处理带有文本的位图图像创建。我会非常感谢你
【解决方案2】:

尝试在 userControl1.Loaded 事件上调用函数 SaveImage()

【讨论】:

  • 首先,谢谢。 Loaded 事件的问题是我实际上必须在窗口关闭时保存到图像中 - 所以我将代码放在窗口的关闭事件中,并且 Usercontrol1 不会触发 Loaded 事件。知道如何做到不同吗?
  • 我不知道我是否应该更新问题,并添加 Closed 事件,最初的想法是在上传之前简化代码。
  • 是的,有道理。如果您在 Closing 事件中调用 SaveImage() 也可以。
【解决方案3】:

如果我这样做,它会起作用,但不确定这是你想要的:

<Window x:Class="DrawImage.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:DrawImage="clr-namespace:DrawImage"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <DrawImage:UserControl1 x:Name="uc" Visibility="Hidden"/>
    </Grid>
</Window>

void MainWindow_Closing(object sender, CancelEventArgs e)
{
    uc.DataContext = "hello";
    uc.Height = 100;
    uc.Width = 100;
    uc.Background = Brushes.LightBlue;
    uc.Visibility = Visibility.Visible;
    DrawToImage(uc);
}

【讨论】:

  • 感谢 Johan Larsson,我不想将 UserControl1 添加到我的 UI 树中,只是将其渲染为图像,将其绘制到树中并赋予它隐藏的可见性在我看来不是作为解决问题的适当方法。 P.S - 我要为很多元素做这个,不想将它们全部添加到我的树中。
【解决方案4】:

编辑

我现在能够重现该问题。如果我在 Window 构造函数中设置 DataContext ,那么它就可以工作。如果我在 Winndow_Closed 事件中设置它,我会得到与你得到的完全相同的结果。

我想可能没有解决方法,因为 WPF 需要一些时间才能在 UI 线程上实际呈现文本。如果在 WPF 在 UI 线程上呈现文本之前呈现 PNG,它将不会出现在 PNG 上。 似乎不存在解决方法,因为在运行Closed 事件处理程序时窗口将被销毁。一方面,当您希望 UI 线程呈现控件时,无法阻止 UI 线程以防止窗口被破坏。

我建议在渲染控件后立即渲染图像,并在关闭窗口时保存图像文件。

【讨论】:

    【解决方案5】:

    我在我的博客中发表了一篇文章(在帐户中输入 png 透明度(导致黑色背景)): Saving FrameworkElement as Image

    FrameworkElement element = myControl.Content;
    // you can set the size as you need.
    Size theTargetSize = new Size(1500,2000)
    element.Measure(new System.Windows.Size(double.PositiveInfinity, double.PositiveInfinity));
    element.Arrange(new Rect(theTargetSize ));
    // to affect the changes in the UI, you must call this method at the end to apply the new changes
    element.UpdateLayout();
    

    您可以在博客文章中找到完整的 cod。

    【讨论】:

      猜你喜欢
      • 2016-05-11
      • 2013-05-31
      • 2012-07-01
      • 2011-05-08
      • 1970-01-01
      • 1970-01-01
      • 2021-07-11
      • 1970-01-01
      相关资源
      最近更新 更多