单击WPF按钮时的方法运行不正常

时间:2021-05-23 21:05:19

This is my XAML part code:

这是我的XAML部件代码:

<DockPanel Margin="1 5 1 0" Height="25">
    <Button DockPanel.Dock="Right" Width="70" Margin="6 0 0 0" Content="Install" Click="Install" />
    <Button DockPanel.Dock="Right" Width="70" Margin="6 0 0 0" Content="Uninstall"/>
    <ProgressBar Name="progressBar"/>
</DockPanel>

And this is the Install method:

这是Install方法:

private void Install(object sender, RoutedEventArgs e)
{
    progressBar.Value = 5;

    installer.InstallProgram1();

    progressBar.Value = 25;

    installer.InstallProgram2();

    progressBar.Value = 50;

    installer.InstallProgram3();

    progressBar.Value = 75;

    installer.InstallProgram4();

    progressBar.Value = 100;
}

When I click the install button, it runs the Install method but not correctly.
- It never executes the first line: 'progressBar.Value = 5'.
- The second line works well.
- And after nothing works.

当我单击安装按钮时,它会运行Install方法但不正确。 - 它永远不会执行第一行:'progressBar.Value = 5'。 - 第二行运作良好。 - 没有任何作用。

I tried to replace my method with 'MessageBox.Show("Hello World")', it works, the progress bar value changes.

我试图用'MessageBox.Show(“Hello World”)'替换我的方法,它工作,进度条值改变。

But why it doesn't work with my methods?
Why 'installer.InstallProgram2()' doesn't work/finish?

但为什么它不能用我的方法?为什么'installer.InstallProgram2()'不起作用/完成?

My two methods, they are inside a Installer.cs file:

我的两个方法,它们在Installer.cs文件中:

public void InstallProgram1()
{
    // Download the lavfilters executable.
    var url = "http://www.videohelp.com/software/LAV-Filters";
    var selector = "a.linktool:nth-child(12)";
    var filename = downloader.DownloadFromVideoHelp(url, selector);

    // TODO: Installation
}

public void InstallProgram2()
{
    // Download the madVR archive
    var url = "http://www.videohelp.com/software/madVR";
    var selector = ".linktool";
    var filename = downloader.DownloadFromVideoHelp(url, selector);

    // TODO: Installation
}

1 个解决方案

#1


4  

Without a good, minimal, complete code example it is not possible to know for sure the best way to address your problem. But some advice can be given to help.

如果没有一个好的,最小的,完整的代码示例,就无法确定解决问题的最佳方法。但是可以提供一些建议来帮助。

First, you write:

首先,你写:

It never executes the first line: 'progressBar.Value = 5'.

它从不执行第一行:'progressBar.Value = 5'。

That is simply false. A debugger would tell you as much. It is just not possible that the first statement in your method would be skipped while the remained are executed.

那简直是假的。调试器会告诉你多少。只有在执行剩余时才会跳过方法中的第一个语句。

As for the remainder of the statements in the method, maybe they work, maybe they don't. Again, lacking a complete code example, there's nothing anyone here at Stack Overflow can do to even comment on that.

至于方法中的其余陈述,也许它们有效,也许它们不起作用。同样,缺少一个完整的代码示例,Stack Overflow中没有任何人可以做甚至评论。

What I can tell you is that the code you posted is going to appear as though the statements assigning progressBar.Value aren't being executed, because you are executing those statements in the UI thread, preventing that thread from doing any on-screen updates until the entire method has completed.

我可以告诉你的是,你发布的代码看起来好像没有执行指定progressBar.Value的语句,因为你在UI线程中执行这些语句,阻止该线程进行任何屏幕更新直到整个方法完成。

It is possible that is all that is wrong with your code. If so, changing your method so that it looks more like this one should help:

您的代码可能有问题。如果是这样,更改您的方法,使其看起来更像这个应该有帮助:

private async void Install(object sender, RoutedEventArgs e)
{
    progressBar.Value = 5;

    await Task.Run(() => installer.InstallProgram1());

    progressBar.Value = 25;

    await Task.Run(() => installer.InstallProgram2());

    progressBar.Value = 50;

    await Task.Run(() => installer.InstallProgram3());

    progressBar.Value = 75;

    await Task.Run(() => installer.InstallProgram4());

    progressBar.Value = 100;
}

What the above does is run your various "installer" methods in a separate thread. It uses the new (as of .NET 4.5) async/await feature to simplify the interaction between the UI thread and the tasks. All of the code in the method itself is still executed in the UI thread, but the (now) anonymous methods that call your "installer" methods are executed using the thread pool.

以上是在单独的线程中运行各种“安装程序”方法。它使用新的(从.NET 4.5开始)async / await功能来简化UI线程和任务之间的交互。方法本身中的所有代码仍然在UI线程中执行,但调用“安装程序”方法的(现在)匿名方法是使用线程池执行的。

C# returns from the Install() method at each await statement, allowing the UI thread to continue operating normally (e.g. updating the UI to reflect the new value for the ProgressBar). When each task is complete, control will return to the Install() method after the await statement for that task; this is repeated until the method reaches its normal return point (e.g. a return statement or, as here, the end of the method body).

C#从每个await语句的Install()方法返回,允许UI线程继续正常运行(例如,更新UI以反映ProgressBar的新值)。当每个任务完成后,控制将返回到该任务的await语句之后的Install()方法;重复这一过程,直到方法到达其正常返回点(例如,返回语句,或者,如此处,方法体的结尾)。

Do beware the usual pitfalls of executing code in different threads. There's nothing in the code example you posted that would suggest the "installer" methods can't be run in a separate thread, but…since the code example is far from complete, that's not really saying much. If you feel that there may be concurrency issues to address, please reduce your problem example to a good code example (see the link I provided above) that sufficiently illustrates those problems, and post a new question asking about those issues specifically.

请注意在不同线程中执行代码的常见缺陷。您发布的代码示例中没有任何内容表明“安装程序”方法无法在单独的线程中运行,但是......因为代码示例远未完成,所以并不是真的说得太多。如果您认为可能存在要解决的并发问题,请将您的问题示例缩减为一个良好的代码示例(请参阅我上面提供的链接),以充分说明这些问题,并发布一个专门询问这些问题的新问题。

#1


4  

Without a good, minimal, complete code example it is not possible to know for sure the best way to address your problem. But some advice can be given to help.

如果没有一个好的,最小的,完整的代码示例,就无法确定解决问题的最佳方法。但是可以提供一些建议来帮助。

First, you write:

首先,你写:

It never executes the first line: 'progressBar.Value = 5'.

它从不执行第一行:'progressBar.Value = 5'。

That is simply false. A debugger would tell you as much. It is just not possible that the first statement in your method would be skipped while the remained are executed.

那简直是假的。调试器会告诉你多少。只有在执行剩余时才会跳过方法中的第一个语句。

As for the remainder of the statements in the method, maybe they work, maybe they don't. Again, lacking a complete code example, there's nothing anyone here at Stack Overflow can do to even comment on that.

至于方法中的其余陈述,也许它们有效,也许它们不起作用。同样,缺少一个完整的代码示例,Stack Overflow中没有任何人可以做甚至评论。

What I can tell you is that the code you posted is going to appear as though the statements assigning progressBar.Value aren't being executed, because you are executing those statements in the UI thread, preventing that thread from doing any on-screen updates until the entire method has completed.

我可以告诉你的是,你发布的代码看起来好像没有执行指定progressBar.Value的语句,因为你在UI线程中执行这些语句,阻止该线程进行任何屏幕更新直到整个方法完成。

It is possible that is all that is wrong with your code. If so, changing your method so that it looks more like this one should help:

您的代码可能有问题。如果是这样,更改您的方法,使其看起来更像这个应该有帮助:

private async void Install(object sender, RoutedEventArgs e)
{
    progressBar.Value = 5;

    await Task.Run(() => installer.InstallProgram1());

    progressBar.Value = 25;

    await Task.Run(() => installer.InstallProgram2());

    progressBar.Value = 50;

    await Task.Run(() => installer.InstallProgram3());

    progressBar.Value = 75;

    await Task.Run(() => installer.InstallProgram4());

    progressBar.Value = 100;
}

What the above does is run your various "installer" methods in a separate thread. It uses the new (as of .NET 4.5) async/await feature to simplify the interaction between the UI thread and the tasks. All of the code in the method itself is still executed in the UI thread, but the (now) anonymous methods that call your "installer" methods are executed using the thread pool.

以上是在单独的线程中运行各种“安装程序”方法。它使用新的(从.NET 4.5开始)async / await功能来简化UI线程和任务之间的交互。方法本身中的所有代码仍然在UI线程中执行,但调用“安装程序”方法的(现在)匿名方法是使用线程池执行的。

C# returns from the Install() method at each await statement, allowing the UI thread to continue operating normally (e.g. updating the UI to reflect the new value for the ProgressBar). When each task is complete, control will return to the Install() method after the await statement for that task; this is repeated until the method reaches its normal return point (e.g. a return statement or, as here, the end of the method body).

C#从每个await语句的Install()方法返回,允许UI线程继续正常运行(例如,更新UI以反映ProgressBar的新值)。当每个任务完成后,控制将返回到该任务的await语句之后的Install()方法;重复这一过程,直到方法到达其正常返回点(例如,返回语句,或者,如此处,方法体的结尾)。

Do beware the usual pitfalls of executing code in different threads. There's nothing in the code example you posted that would suggest the "installer" methods can't be run in a separate thread, but…since the code example is far from complete, that's not really saying much. If you feel that there may be concurrency issues to address, please reduce your problem example to a good code example (see the link I provided above) that sufficiently illustrates those problems, and post a new question asking about those issues specifically.

请注意在不同线程中执行代码的常见缺陷。您发布的代码示例中没有任何内容表明“安装程序”方法无法在单独的线程中运行,但是......因为代码示例远未完成,所以并不是真的说得太多。如果您认为可能存在要解决的并发问题,请将您的问题示例缩减为一个良好的代码示例(请参阅我上面提供的链接),以充分说明这些问题,并发布一个专门询问这些问题的新问题。