WPF字节数组到ImageSource,而不使用MemoryStream

本文关键字:MemoryStream ImageSource 字节 字节数 数组 WPF | 更新日期: 2023-09-27 18:28:05

我有一个应用程序,它可以动态创建WPF图像控件,以显示SQL Server数据库表中的图像。显示控件的面板经常被更换。我使用MemoryStream允许控件访问从数据库加载的字节数组。我无法关闭这些流,只要图像控件已显示并且仍显示图像即可。我担心的是,这些流将一直处于打开状态,直到垃圾回收器能够处理Image控件并希望关闭这些流。我最终可能只会确保在更换面板之前关闭流或处理图像控件,但我想知道是否存在打开这些流的问题,以及是否有办法解决这一问题。

这是我正在使用的代码。

public class ImageToSql
{
    private static OpenFileDialog _openFileDialog = new OpenFileDialog();
    static ImageToSql()
    {
        _openFileDialog = new OpenFileDialog();
        _openFileDialog.AddExtension = true;
        _openFileDialog.CheckFileExists = true;
        _openFileDialog.DefaultExt = ".jpg";
        _openFileDialog.Filter = "JPEG files (*.jpg)|*.jpg|All files (*.*)|*.*";
        _openFileDialog.FilterIndex = 1;
        _openFileDialog.Multiselect = false;
    }
    public static BitmapImage LoadImageFromFile(string caption)
    {
        BitmapImage bi = new BitmapImage();
        _openFileDialog.Title = caption;
        if (_openFileDialog.ShowDialog() == true)
        {
            bi.BeginInit();
            bi.StreamSource = File.OpenRead(_openFileDialog.FileName);
            bi.EndInit();
        }
        return bi;
    }
    public static int StoreImage(string connectionString, string sql, string imageParameterName, BitmapImage bitmapImage)
    {
        SqlConnection conn = new SqlConnection(connectionString);
        try
        {
            conn.Open();
            sql += ";SELECT @@IDENTITY";
            using (SqlCommand cmd = new SqlCommand(sql, conn))
            {
                byte[] data = new byte[bitmapImage.StreamSource.Length];
                bitmapImage.StreamSource.Seek(0, SeekOrigin.Begin);
                bitmapImage.StreamSource.Read(data, 0, data.Length);
                cmd.Parameters.Add(imageParameterName, System.Data.SqlDbType.VarBinary, -1).Value = data;
                object obj = cmd.ExecuteScalar();
                return Int32.Parse(obj.ToString());
            }
        }
        finally
        {
            conn.Close();                
        }
    }
    public static BitmapImage RetrieveImage(string connectionString, string sql, string imageIDParameterName, int imageID)
    {
        BitmapImage bi = new BitmapImage();
        SqlConnection conn = new SqlConnection(connectionString);
        try
        {
            conn.Open();
            using (SqlCommand cmd = new SqlCommand(sql, conn))
            {
                cmd.Parameters.Add(imageIDParameterName, System.Data.SqlDbType.Int).Value = imageID;
                byte[] data = (byte[])cmd.ExecuteScalar();
                MemoryStream ms = new MemoryStream(data);
                ms.Seek(0, SeekOrigin.Begin);
                bi.BeginInit();
                bi.StreamSource = ms;
                bi.EndInit();
            }
        }
        finally
        {
            conn.Close();
        }
        return bi;
    }
}

以下是如何调用此代码。"_fileImage"answers"_sqlImage"是我的测试窗口上的图像控件。有一次,我在"LoadImageFromFile"中使用流从磁盘读取文件,并认为我能够关闭该流,同时仍在image控件中显示图像。所以,MemoryStream似乎在某种程度上很特别。

        BitmapImage bi = ImageToSql.LoadImageFromFile("Select Image to Save");
        _fileImage.Source = bi;
        int imageID = ImageToSql.StoreImage(connString,
            "INSERT INTO PV_Image (Description, Image) VALUES ('Some Image', @pImage)",
            "@pImage", bi);
        _sqlImage.Source = ImageToSql.RetrieveImage(connString, 
            "SELECT Image FROM PV_Image WHERE ImageID = @pImageID", 
            "@pImageID", imageID);

WPF字节数组到ImageSource,而不使用MemoryStream

一旦使用内存流,就可以使用以下使用模式处理它:

using (Stream stream = new MemoryStream(data))
{
    BitmapImage image = new BitmapImage():
    stream.Position = 0;
    image.BeginInit();
    image.CacheOption = BitmapCacheOption.OnLoad;
    image.StreamSource = stream;
    image.EndInit();
    image.Freeze();
    return image;
}