从edge拖图片到wpf应用程序下载的相关问题个人记录

创作原因

闲来无事突然想把图片拖到wpf程序让他下载,然后出现了一堆问题,记录一下,免得下次折腾

问题过程

这是一张图片(小特,可爱!)
breadman的小特表情包
这是一个普通的wpf程序
在这里插入图片描述

右侧的图片栏就是万恶之源

在xaml中我给他添加了一个接受拖放的功能

<i:Interaction.Triggers>
  <i:EventTrigger EventName="Drop">
    <i:InvokeCommandAction Command="{Binding OnDropImageCommand}" PassEventArgsToCommand="True" />
  </i:EventTrigger>
</i:Interaction.Triggers>
        private void OnDropImage(DragEventArgs e)
        {
            ImageBar imageBar = new();
            Uri? uri = null;
            if (e.Data.GetDataPresent("System.String"))
            {
                if(e.Data.GetData("System.String") is string obj && obj != null)
                {
                    try
                    {
                        uri = new(obj);
                        Bitmap bitmap= BitmapService.Get(uri);
                    }
                    catch(Exception ex)
                    {
                        RaiseConfirm(ex.Message);
                    }
                }
            }
            if(uri!=null)
            {
                Images.Add(imageBar);
                JsonReader.Save(ImageTag, Images);
            }
        }

BitmapService.Get是用于获取图像的

一切都是水到渠成,那么合理,来,运行一下
轻轻的把图片拖上去
万籁此俱寂
卡了……都卡了,连edge都卡了……
(发现连带着edge都卡了还是在测试了好几遍内部程序没问题才发现的)

问题分析

这是BitmapService.Get的实现

public static Bitmap Get(Uri uri)
{
    string name = Path.GetFileName(uri.ToString());
    string extension = Path.GetExtension(uri.ToString());
    string path = Path.Combine(PathConstants.Instance.Images, name);
    if (File.Exists(path))
    {
        return Get(path);
    }
    BitmapImage bitmapImage = GetFromUri(uri);

    //需要释放流,否则无法读取图像
    using (var fileStream = new FileStream(path, FileMode.OpenOrCreate))
    {
        BitmapEncoder encoder = ImageEncoder.SetExtension(extension);
        encoder.Frames.Add(BitmapFrame.Create(bitmapImage));
        encoder.Save(fileStream);
    }
    return Get(name);
}

读取本地文件没有一点压力,重点就是从网络中读取文件

罪魁祸首

private static async Task<BitmapImage> GetFromHttp(Uri uri)
{
    BitmapImage bitmapImage = new();
    byte[] origin =await HttpClient.GetByteArrayAsync(uri);
    using (MemoryStream fs=new(origin))
    {
        bitmapImage.BeginInit();
        bitmapImage.StreamSource = fs;
        bitmapImage.EndInit();
    }
    return bitmapImage;
}

根据我自己的分析,大概是这样一个过程

edge给程序发送拖动的文件,在完成对拖动操作的执行结束之前,wpf又向edge发送 HttpClient请求,然后就像陷入死锁了一样两个一起不动了

解决问题

第一想法

你卡我,我卡你,那我拿新线程跑不就行了

然后就这样改了

OnDropImage

try
{
    uri = new(obj);
    Thread thread = new(() =>
    {
        Bitmap bitmap = BitmapService.Get(uri);
    });
    thread.Start();
    thread.Join();
}

然后又爆出这样的问题,更稀罕了

在这里插入图片描述
然后又是一通检查,从uri开查,查过一通之后才开始怀疑BitmapImage

最后才发现一个特性,BitmapImageBitmapImage.EndInit() 操作必须在UI线程上实现,不是随便什么线程都能更新的

然后在一通修改后就变这样了……

private void OnDropImage(DragEventArgs e)
{
    ImageBar imageBar = new();
    Uri? uri = null;
    if (e.Data.GetDataPresent("System.String"))
    {
        if(e.Data.GetData("System.String") is string obj && obj != null)
        {
            try
            {
                uri = new(obj);
                imageBar.Title=System.IO.Path.GetFileName(obj);
                imageBar.ImageSource= BitmapService.Get(uri);
            }
            catch(Exception ex)
            {
                RaiseConfirm(ex.Message);
            }
        }
    }
    if(uri!=null)
    {
        Images.Add(imageBar);
        JsonReader.Save(ImageTag, Images);
    }
}
//从网络获取图像
private static async Task<byte[]> GetFromHttp(Uri uri)
{
    byte[] origin =await HttpClient.GetByteArrayAsync(uri);
    return origin;
}

public static BitmapImage GetFromUri(Uri uri)
{
    if (uri.ToString().StartsWith("http"))
    {
        MemoryStream memoryStream = new();
        Thread thread = new(() =>
        {
            memoryStream = new(GetFromHttp(uri).Result);
        });
        thread.Start();
        thread.Join();
        BitmapImage bitmapImage = new();
        bitmapImage.BeginInit();
        bitmapImage.StreamSource = memoryStream;
        bitmapImage.EndInit();
        return bitmapImage;
    }
    else if (uri.ToString().StartsWith("file"))
    {
        return GetFromLocal(uri);
    }
    else
    {
        throw new InvalidDataException($"{uri}\n无法识别的数据");
    }
}

怎么真解决了感觉这问题这么傻呢……
算了,解决了就是好事,现在的问题是下载的时候UI也在等(好歹不是忙等了),之后再想办法怎么解决吧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值