序列化WPF图像 [英] Serializing a WPF Image

查看:152
本文介绍了序列化WPF图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在试图了解图像序列化在WPF中的工作原理。我有以下类:

I'm trying to understand how image serialization works in WPF. I have the following class:

[Serializable]
public class TestClass : ISerializable
{
    public TestClass() { }


    protected TestClass(SerializationInfo info, StreamingContext context)
    {
        SerializedImage = (byte[])info.GetValue("SerializedImage", typeof(byte[]));
    }


    public byte[] SerializedImage { get; set; }


    public Image Image { get; set; }


    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("SerializedImage", SerializedImage);
    }


    [OnSerializing]
    private void OnSerializing(StreamingContext sc)
    {
        BitmapImage image = Image.Source as BitmapImage;

        MemoryStream stream = new MemoryStream();
        BmpBitmapEncoder encoder = new BmpBitmapEncoder();
        encoder.Frames.Add(BitmapFrame.Create(image));
        encoder.Save(stream);

        SerializedImage = stream.ToArray();

        stream.Close(); ;
    }


    [OnDeserialized]
    private void OnDeserialized(StreamingContext sc)
    {
        MemoryStream stream = new MemoryStream(SerializedImage);
        Image = new Image
        {
            Source = BitmapFrame.Create(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad)
        };

        stream.Close();
    }
}

这是Xaml代码:

<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="358" Width="300" ResizeMode="NoResize">
<StackPanel>

    <Image x:Name="Screenshot" Height="178" />
    <Button Width="80" Height="30" Content="Load Image" Click="Button_Click_1" />
    <Button Width="92" Height="30" Content="Save to file" Click="Button_Click_2" />
    <Button Width="92" Height="30" Content="Load File" Click="Button_Click_3" />
    <Button Width="92" Height="30" Content="Load File (1)" Click="Button_Click_4" />

</StackPanel>

这是代码背后:

public partial class Window1 : Window
{
    TestClass test;


    public Window1()
    {
        InitializeComponent();

        test = new TestClass();
    }


    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        OpenFileDialog dialog = new OpenFileDialog { Filter = "Bmp Image | *.bmp" };
        dialog.ShowDialog();

        if (dialog.FileName != string.Empty)
        {
            Screenshot.Source = new BitmapImage(new Uri(dialog.FileName));
            test.Image = Screenshot;
        }
    }


    private void Button_Click_2(object sender, RoutedEventArgs e)
    {
        SaveFileDialog dialog = new SaveFileDialog { DefaultExt = ".t", AddExtension = true };
        dialog.ShowDialog();

        if (dialog.FileName != string.Empty)
        {
            BinaryFormatter formatter = new BinaryFormatter();
            FileStream stream = new FileStream(dialog.FileName, FileMode.Create);
            formatter.Serialize(stream, test);
            stream.Close();
        }
    }


    private void Button_Click_3(object sender, RoutedEventArgs e)
    {
        OpenFileDialog dialog = new OpenFileDialog { Filter = "TEST file | *.t" };
        dialog.ShowDialog();

        if (dialog.FileName != string.Empty)
        {
            BinaryFormatter formatter = new BinaryFormatter();
            FileStream stream = new FileStream(dialog.FileName, FileMode.Open);
            test = formatter.Deserialize(stream) as TestClass;
            stream.Close();

            Screenshot = test.Image;
        }
    }


    private void Button_Click_4(object sender, RoutedEventArgs e)
    {
        OpenFileDialog dialog = new OpenFileDialog { Filter = "TEST file | *.t" };
        dialog.ShowDialog();

        if (dialog.FileName != string.Empty)
        {
            BinaryFormatter formatter = new BinaryFormatter();
            FileStream stream = new FileStream(dialog.FileName, FileMode.Open);
            test = formatter.Deserialize(stream) as TestClass;
            stream.Close();

            Screenshot.Source = null;

            MemoryStream stream1 = new MemoryStream(test.SerializedImage);
            Screenshot.Source = BitmapFrame.Create(stream1, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
        }
    }
}

现在由于某种原因我不知道,TestClass中的图像的反序列化效果不好。如果我抓住字节数组并将其自身转换回到一个图像(Button_Click_4),它可以工作,图像显示在我的表单上。如果相反,我直接从TestClass中的Image属性获取图像,则表单上不会显示任何内容。我不知道这是可能的,因为这两种情况下的代码都是一样的,除非在幕后发生其他事情。

Now for some reason that I don't know, the deserialization of the image in TestClass is not working well. If I grab the byte array and convert it back to an image myself (Button_Click_4), it works and the image is shown on my form. If, instead, I grab the image directly from the Image property in TestClass, nothing will show on the form. I don't know how this is possible, since the code involved in both situations is the same, unless something else is happening behind the scenes.

我做错了什么?我提供了完整的代码,你可以粘贴它并运行它来查看问题。

What am I doing wrong? I have provided the complete code, you can paste it and run it to see the problem.

推荐答案

树被称为屏幕截图的字段引用。将这个.Screenshot分配给一个新的图像根本不会改变你的视觉树。它只是分配字段的屏幕截图。在您设置Source的情况下,您正在更新视觉树中的图像。

The Image object in your visual tree is referenced by a field called "Screenshot". Assigning this.Screenshot to a new Image does not alter your visual tree at all. It just assigns the field Screenshot. In the case where you set the Source, you are updating the Image that is in your visual tree.

理想情况下,您的测试类应公开一个ImageSource属性,而不是图像。单个Image实例只能在可视树中出现一次。因此,通过暴露一个ImageSource属性,您可以在Image的多个实例中重用它(可以在您的视觉树中的各个位置使用)。

Ideally, your test class should expose an ImageSource property, not an Image. A single Image instance can only appear once in the visual tree. So by exposing an ImageSource property, you can reuse that in several instances of Image (that may be used in various locations in your visual tree).

这篇关于序列化WPF图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆