我试图了解 .NET 4.5 中的变化,主要是异步功能。为了解决这个问题,我想我会创建一个小应用程序来归档我的大量照片集。通过这样做,我学得最好,该应用程序具有双重目的。
我已经阅读了很多关于使用异步的 MSDN 文章,但我认为我对它的理解不够好(因为它不起作用)。我的意图是将源文件夹中的每张照片根据拍摄日期复制到目标文件夹(或者如果拍摄的元数据丢失则创建)。同时将其重命名为标准命名约定,并在图像框中存档图像时显示图像。我希望应用程序在工作期间保持响应,这就是异步的用武之地。现在应用程序的目的并不重要,重点是让我的头脑围绕异步。
实际发生的是应用程序无响应,按预期归档所有图像,但图像框仅显示最终图片。异步开始文件传输然后继续下一个图像,开始传输然后继续等等等等,所以我最终得到了数百个打开的文件流,而不是等待每个文件关闭。
任何我出错的地方都将不胜感激。我对使用任务的理解是不稳定的,返回任务有什么用?
imgMain 是 XAML 文件中的图像框。async/await 在存档方法中,但显示所有可能相关的代码。
using System;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Windows.Forms;
using System.IO;
namespace PhotoArchive
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    private string Source 
    {
        get { return txtSource.Text; }
        set { txtSource.Text = value; }
    }
    private string Destination
    {
        get { return txtDestination.Text; }
        set { txtDestination.Text = value; }
    }
    public MainWindow()
    {
        InitializeComponent();
    }
    private void btnBrowseDataSource_Click(object sender, RoutedEventArgs e)
    {
        var dialogue = new FolderBrowserDialog();
        dialogue.ShowDialog();
        Source = dialogue.SelectedPath;
    }
    private void btnBrowseDestination_Click(object sender, RoutedEventArgs e)
    {
        var dialogue = new FolderBrowserDialog();
        dialogue.ShowDialog();
        Destination= dialogue.SelectedPath;
    }
    private void btnSort_Click(object sender, RoutedEventArgs e)
    {
        var files = Directory.GetFiles(Source, "*.*", SearchOption.AllDirectories);
        var result = from i in files
                     where i.ToLower().Contains(".jpg") || i.ToLower().Contains(".jpeg") || i.ToLower().Contains(".png")
                     select i;
        foreach (string f in result)
        {
            DateTime dest = GetDateTakenFromImage(f);
            Archive(f, Destination, dest);
        }
    }
    private async void Archive(string file, string destination, DateTime taken)
    {
        //Find Destination Path
        var sb = new StringBuilder();
        sb.Append(destination);
        sb.Append("\\");
        sb.Append(taken.ToString("yyyy"));
        sb.Append("\\");
        sb.Append(taken.ToString("MM"));
        sb.Append("\\");
        if (! Directory.Exists(sb.ToString()))
        {
            Directory.CreateDirectory(sb.ToString());
        }
        sb.Append(taken.ToString("dd_MM_yyyy_H_mm_ss_"));
        sb.Append((Directory.GetFiles(destination, "*.*", SearchOption.AllDirectories).Count()));
        string[] extension = file.Split('.');
        sb.Append("." + extension[extension.Length-1]);
        using (FileStream fs = File.Open(file, FileMode.Open))
        using (FileStream ds = File.Create(sb.ToString())) 
        {
            await fs.CopyToAsync(ds);
            fs.Close();
            File.Delete(file);
        }
        ImgMain.Source = new BitmapImage(new Uri(sb.ToString()));
    }
    //get date info
    private static Regex r = new Regex(":");
    public static DateTime GetDateTakenFromImage(string path)
    {
        using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read))
        {
            using (System.Drawing.Image img = System.Drawing.Image.FromStream(fs, false, false))
            {
                PropertyItem prop;
                try
                {
                    prop = img.GetPropertyItem(36867);
                }
                catch (Exception)
                {
                    prop = img.GetPropertyItem(306);
                }
                string dateTaken = r.Replace(Encoding.UTF8.GetString(prop.Value), "-", 2);
                return DateTime.Parse(dateTaken);
            }
        }
    }
}
}