gpt4 book ai didi

c# - Form级别的进度声明给出了异常

转载 作者:太空宇宙 更新时间:2023-11-03 21:27:34 24 4
gpt4 key购买 nike

在 WPF 窗口中,在控制台应用程序中启动,我尝试了这个示例以在 async-await 中使用 IProgress:

namespace Test
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Main : Window
{
// class level declaration
Progress<string> Progress1;

public Main()
{
InitializeComponent();

// initialization of class level field
Progress1 = new Progress<string>(value =>
{
Print(value);
});
}

private async void Button_Click(object sender, RoutedEventArgs e)
{
Print("Start test");

// local variable
Progress<string> Progress2 = new Progress<string>(value =>
{
Print(value);
});

// interface (normally Progress1/2 would be passed as a parameter)
// Progress2 works fine, Progress1 gives an exception
var progress = Progress1 as IProgress<string>;

await Task.Run(() =>
{
for (int i = 0; i != 5; ++i)
{
if (progress != null) progress.Report("\nStage " + i);
Thread.Sleep(1000);
}
});

Print("\nCompleted.");
}

void Print(string text)
{
//Output is a WPF TextBlock
Output.Inlines.Add(new Run(text) { Foreground = Brushes.Blue, FontWeight = FontWeights.Normal });
}
}

局部变量 Progress2 工作正常:回调在 UI 线程中。
类级别字段 Progress1 给出了一个异常。这个回调显然在后台线程中。

The calling thread cannot access this object because a different thread owns it.

这可能与匿名函数和回调的工作方式有关。
有人可以解释一下这个问题吗?

编辑
该问题无法在普通 WPF 解决方案中重现。
它可以在启动 WPF 窗口的控制台应用程序中重现,如下所示:

Application app = new Application ();
app.Run(new Main());

在那种情况下,构造函数中的 Synchronization.Current == null 并且它是 != null 例如Loaded 事件。如答案和评论中所述。

最佳答案

是的,请给 Microsoft 买支雪茄,以便将此诊断程序构建到 Winforms 中,否则这将是一个完全无法调试的问题,只会偶尔使您的代码崩溃。

这是一个初始化顺序问题,它是由您的 Progress 变量初始化太早引起的。请记住 Progress<> 类的作用,它知道如何运行您在“正确的线程”上传递的委托(delegate)的目标。特别是,您希望它在您的 UI 线程上运行,以便您可以安全地更新标签。 Progress<> 通过制作 SynchronizationContext.Current 的副本来做到这一点,稍后使用它通过其 Post() 方法运行委托(delegate)目标。

问题是,Current 属性还没有值。几微秒后,当 Form 基类构造函数运行时,就会发生这种情况。 Progress<> 复制了一个 null,它现在唯一能做的就是在线程池线程上运行 Post() 方法目标。砰!

修复很简单:

Progress<string> Progress;

public Form1() {
InitializeComponent();
Progress = new Progress<string>(value => {
label.Text = value;
});
}

现在后面初始化,Synchronization.Current有值。

关于c# - Form级别的进度声明给出了异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26090493/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com