[英]Why is SynchronizationContext.Current null in my Winforms application?
[英]Why is SynchronizationContext.Current null?
错误: Object reference not set to an instance of an object.
下面的算法有效。 我试过了,然后我将null
项目删除到另一个目录, SynchronizationContext.Current
是Winform
。 为什么?
SynchronizationContext uiCtx = SynchronizationContext.Current;
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
int[] makeSelfMoves = new int[4];
lock (replay)
{
// count should be more than 2
foreach (KeyValuePair<int, int[]> item in replay)
{
makeSelfMoves = replay[item.Key];
codeFile.ExecuteAll(makeSelfMoves[0],
makeSelfMoves[1], makeSelfMoves[2], makeSelfMoves[3]);
// i get the error here. uictx is null
uiCtx.Post(o =>
{
PrintPieces(codeFile.PieceState());
}, null);
System.Threading.Thread.Sleep(1000);
}
}
}
您的代码主要取决于 class 的构造函数运行的确切时间和位置。 SynchronizationContext.Current 在以下情况下将为 null:
您的 class object 创建得太早,在您的代码创建表单 class 的实例或调用 Main() 中的 Application.Run() 之前。 那时 Current 成员被设置为 WindowsFormsSynchronizationContext 的一个实例,class 知道如何使用消息循环编组调用。 通过将 object 实例化代码移动到主窗体构造函数来解决此问题。
您的 class object 是在主 UI 线程以外的任何线程上创建的。 只有 Winforms 应用程序中的 UI 线程可以编组调用。 通过使用以下语句向 class 添加构造函数来诊断此问题:
Console.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId);
还要将此行添加到 Program.cs 中的 Main() 方法。 如果 Output window 中的显示值不同,它将不起作用。 通过将 object 实例化代码再次移动到主窗体构造函数来解决此问题,这样您就可以确保它在 UI 线程上运行。
在我的测试框架中通过依赖注入创建 WinForms 时遇到了这个问题。 最初我会在我的构造函数中捕获 SynchronizationContext.Current:
private readonly SynchronizationContext UISyncCtxt;
public MyWinFormViewModel ()
{
UISyncCtxt = SynchronizationContext.Current;
...
}
如果这个 MyWinFormViewModel 是在应用程序已经运行时创建的,这很好用,但在测试工具中创建依赖关系图时不一定是这种情况。 当由测试工具创建时,SynchronizationContext.Current 将为 null,稍后会出现 null 引用异常。
我的解决方案是“懒惰地”评估它,如下所示:
private SynchronizationContext _uisyncctxt;
private SynchronizationContext UISyncCtxt =>
_uisyncctxt ??= SynchronizationContext.Current;
当我真正需要上下文(更新表单上的控件)时,它肯定存在(因为表单已经被实例化)。
编辑:Peter Duniho 提出了一个关于任意获取同步上下文的有效观点。 我的原始答案也使这个 class 对其依赖关系不诚实,因为它依赖于这个上下文,但没有通过构造函数或其他可注入方法请求它。 由于这个 class 使用 DI,我添加了一个名为 IUISyncContext 的依赖项,它具有以下签名:
public interface IUISyncContext
{
SynchronizationContext UISyncContext { get; }
}
...以及我认为 model 的构造函数:
private readonly SynchronizationContext UISyncCtxt;
public MyWinFormViewModel (IUISyncContext syncContext)
{
UISyncCtxt = syncContext.UISyncContext;
...
}
感谢您的反馈,彼得。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.