65.9K
CodeProject 正在变化。 阅读更多。
Home

使用后台线程、ListView 和 ProgressBar 扫描图像尺寸

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.29/5 (4投票s)

2009年10月12日

CPOL

1分钟阅读

viewsIcon

34589

downloadIcon

2130

扫描图像尺寸可能需要几毫秒,因此在扫描多张图像时,后台线程会很有用。进度会更新到 ListView 并显示在 ProgressBar 中。

screen.png

引言

这篇文章是另一篇文章的扩展版本,我发现这篇文章非常有趣,名为 后台线程和支持取消,作者是 Andrew D. Weiss

本文解释了如何异步运行 BackgroundWorker 线程以扫描图像尺寸。用户可以选择一个文件夹或选择特定的图像。在将图像名称插入 ListView 后,将集合对象传递给 BackgroundWorker,该线程扫描每张图像并报告进度,并在 ProgressBar 上显示。

使用代码

当添加照片时,它们存储在一个名为 PhotoCollection 的对象中,该对象继承自 List<Photo>。每张照片都有一个 FileInfo 实例和一些添加的属性。PhotoCollection 可以导出到 XML 文件,并使用 XmlParser 类从 XML 文件导入回来。

此软件可以进一步扩展为调整大小程序、重命名器、组织器,或者您想对照片集合执行的任何操作。BackgroundWorker 还可以预生成缩略图,并且 ListView 可以替换为类似于 Windows XP 或更高版本中看到的“大图标”视图。

BackgroundWorker

方法 UpdateListView_HeavyProcess() 启动线程并为其提供工作参数。方法 worker_DoWork() 将运行繁重的工作,并且每次在 worker_DoWork() 内部调用 trd.ReportProgress() 时,都会调用方法 worker_ProgressChanged(),该方法允许更新 GUI 组件。当线程完成其工作后,将调用方法 worker_RunWorkerCompleted(),该方法将结果转换为 PhotoCollection

private void UpdateListView_HeavyProcess()
{
    // Do not try to execute the background worker if 
    // he is already busy with work
    if (!worker.IsBusy)
    {
        // Prepare the progress var
        prbProgress.Minimum = 0;
        prbProgress.Maximum = photos.Count;
        prbProgress.Value = 0;
        prbProgress.Step = 1;
        prbProgress.Enabled = true;

        // Run the worker thread, taking photos as argument
        worker.RunWorkerAsync(photos);
    }
}

private void worker_DoWork(object sender, DoWorkEventArgs e)
{
    // Create an instance that represents the running thread
    BackgroundWorker trd = sender as BackgroundWorker;

    // Cast the argument object to PhotoCollection
    PhotoCollection col = (PhotoCollection)e.Argument;
    Image img;

    // Go through each photo using indices
    for (int i = 0; i < col.Count; i++)
    {
        // If the photo HAS dimention - cancel the operation because 
        // it is VERY unlikely that the photo will be changed when
        // already added to this list
        if (col[i].PixelHeight == 0 && col[i].PixelWidth == 0)
        {
            img = Image.FromFile(col[i].FullName);
            col[i].PixelWidth = (int)img.PhysicalDimension.Width;
            col[i].PixelHeight = (int)img.PhysicalDimension.Height;
        }

        // Report back the photo number and scanned dimention
        trd.ReportProgress(i, col[i].Dimention);

        // If the thread MUST stop running!
        if (trd.CancellationPending)
        {
            // Set the e.Cancel flag so that the WorkerCompleted event
            // knows that the process was canceled.
            e.Cancel = true;

            // Save the changed object to result
            e.Result = col;

            // Report back negative value, indicating that the execution is done
            trd.ReportProgress(-1);

            // Stop running the working method
            return;
        }
    }

    // Save the changed object to result
    e.Result = col;

    // Report back negative value, indicating that the execution is done
    trd.ReportProgress(-1);
}

private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // Cast the results to the PhotoCollection object
    // owned by this thread
    photos = (PhotoCollection)e.Result;

    // Now update the whole list again!
    this.UpdateListView(true);

    // Reset the progress bar
    prbProgress.Minimum = 0;
    prbProgress.Value = 0;
    prbProgress.Enabled = false;
}

private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    try
    {
        // Update the title bar at top that the program is working on some photos
        this.Text = "<" + photos[e.ProgressPercentage].Name + 
                    "> " + ProgramName;

        // Perform a progress step
        prbProgress.PerformStep();

        // Try to update the ListView by using the progress percentage
        // as an index in the ListView items
        lsvFiles.Items[e.ProgressPercentage].SubItems[2].Text = e.UserState.ToString();
    }
    catch
    {
        this.Text = ProgramName;
    }
}
© . All rights reserved.