如何等待方法(在继续使用其他方法/过程/功能)之前完成



原谅我的语义和编程无知。我想运行一种方法,然后等待它在继续之前完成。最初的方法拨打了其他2个电话,我无法弄清楚如何/何时将"继续完成下一步仅在您完全完成之后"。

搜索时,我遇到了各种同步和异步方法的方式。

  1. 我尝试使用Task t = Task.Run(() => startDownload(BTurl, BTlocation))Task.WaitAll()t.wait()一起使用,没有运气。

  2. 尝试等待着,但这些方法不是async。(尽管startDownloading()呼叫AsyncCompletedEventHandler(),这会导致我的很多混乱(。

  3. 在各个位置尝试使用_ready.SetEventWaitHandle(请参阅注释的位置A,B和C带有发现(。

  4. 接下来是在类和_resetEvent.Set()resetEvent.WaitOne()下添加private readonly ManualResetEvent _resetEvent = new ManualResetEvent(false);,类似于EventWaitHandle

  5. 我在startDownload()中尝试了thread.Join()。没有欢乐。

  6. startDownload()尝试了Process.Start.......WaitForExit()。nope

我知道我到了某个地方,但没有任何地方。由于某种原因,我可能需要将(?(startDownload()转换为async方法。这是我的困惑所在的地方,因为我的搜索结果证明了如何"等待"从单个方法中,我正在使用的方法对其他两个方法进行调用。

最后,对我来说,这是一个漫长的和学习项目。虽然我可能会跳得太深。[脸红]

namespace Download_Extract
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        //static EventWaitHandle _ready = new AutoResetEvent(false);
        //static EventWaitHandle _go = new AutoResetEvent(false);

        // ***Download and extract***
        private void Button1_Click(object sender, EventArgs e)
        {
            string BTurl = "https://the/file/is/located/here/self_extracting_7z_file.exe";
            string BTlocation = Path.Combine(Path.GetTempPath(), "self_extracting_7z_file.exe");
            startDownload(BTurl, BTlocation);
            //_ready.WaitOne();             //wait here until _ready.Set() is retruned
            label3.Text = "Extracting Files.......";    //_ready.Set() has been received
            Process.Start(BTlocation, @"-aoa -y -oc:dest_folder").WaitForExit();
            label3.Text = "Extracting Files Completed";
        }
        private void startDownload(string BTurl, string BTlocation)
        {
            Thread thread = new Thread(() => {
                WebClient client = new WebClient();
                client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
                client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
                client.DownloadFileAsync(new Uri(BTurl), BTlocation);
            });
            thread.Start();
            //_ready.Set();     // test C  *ProgressBar works, but doesn't wait for completed dl before continuing
        }
        void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            this.BeginInvoke((MethodInvoker)delegate {
                double bytesIn = double.Parse(e.BytesReceived.ToString());
                double totalBytes = double.Parse(e.TotalBytesToReceive.ToString());
                double percentage = bytesIn / totalBytes * 100;
                label3.Visible = true;
                label3.Text = "Downloading.... "; // + e.BytesReceived + " of " + e.TotalBytesToReceive;
                label10.Visible = true;
                label10.Text = String.Format("{0:0}", percentage) + "%";
                progressBar1.Visible = true;
                progressBar1.Value = int.Parse(Math.Truncate(percentage).ToString());
            });
            //_ready.Set();     // test B  *ProgressBar works, but doesn't wait for completed dl before continuing
        }
        void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
        {
            this.BeginInvoke((MethodInvoker)delegate {
                label10.Visible = false;
                label3.Text = "Download completed.";
            });
            //_ready.Set();     // test A  *works, but with issues. pBar delayed, no #%.text shown
        }
    }
}

button1_click的期望结果:下载文件。 下载时,显示进度栏和%完整...下载完成后提取文件。

错误我得到:

消息=该过程无法访问该文件,因为它是由另一个过程使用的

(在下载时尝试提取(

这是async的经典用例,因为您似乎正在走向。

_ready.WaitOne();             //wait here until _ready.Set() is returned

是您的问题,因为它阻止了调用线程,在这种情况下是 ui 螺纹。因此,应用程序冻结并且没有更新文本/进度条。经典解决方案是使用TaskCompletionSource

private TaskCompletionSource<bool> _downloadSource;

您的按钮点击变为:

private async void Button_Click(…)
{
    _downloadSource = new TaskCompletionSource<bool>();
    // Start download
    await _downloadSource.Task
    // Extract
 }

async关键字仅允许您使用await。请注意,async void是不好的练习,除了活动处理程序(有关原因的很多好内容(。

最后下载完成时:

  _downloadSource.TrySetResult(true);

这与AutoResetEvent相同,但异步。C#的意思是方法调用块,但允许线程运行。任务系统将在任务完成时返回原始调用上下文(至少默认情况下(。MSDN有更多有关异步/等待和Task/Task<T>

的信息。

最新更新