public void RefreshData()
{
// this is called on UI thread
List<ds> dataSource;
GetDsDelegate caller = GetDs;
caller.BeginInvoke(out dataSource, RefreshCallback, null);
}
private void RefreshCallback(IAsyncResult ar)
{
// this is called on worker thread
try
{
var result = (AsyncResult)ar;
var caller = (GetDsDelegate)result.AsyncDelegate;
List<ds> dataSource;
var success = caller.EndInvoke(out dataSource, ar);
if (success)
{
BeginInvoke(new Action<List<ds>>(SetGridDataSource), dataSource);
}
}
catch
{
// NOTE: It's possible for this form to close after RefreshData is called
// but before GetDs returns thus the SetGridDataSource method no longer exists.
// Not catching this error causes the entire application to terminate.
}
private void SetGridDataSource(List<ds> dataSource)
{
// this is called on UI thread
dataGrid.DataSource = dataSource;
}
RefreshData,RefreshCallback和SetGridDataSource都是Windows窗体类的方法。调用RefreshData使用GetDsDelegate委托调用外部方法GetDs。当GetDs完成时,它调用RefreshCallback(现在在一个单独的线程上)。最后,调用SetGridDataSource来完成更新。
除非GetDs延迟且表单关闭,否则所有这些工作正常。然后当GetDs完成并调用RefreshCallback时,SetGridDataSource不再存在。
除了显示的try / catch块之外,还有更好的方法来处理这个条件吗?我宁愿防止错误而不是忽略它。有没有更好的模式可供使用?
修改
当我看到错误时,很明显将if (success)
更改为if (success && IsHandleCreated)
以防止它,但看起来我似乎做错了,或者至少很尴尬。我也可以用Invoke替换第二个BeginInvoke,因此不需要EndInvoke。我喜欢将逻辑移离表单的想法,但我不知道结果会如何改变。我认为BackgroundWorker也会遇到同样的问题;作为回调不再可访问。我想结果可能会引发一个事件,但这看起来有点抽象。你能详细说明一下还是提供一个例子。
答案 0 :(得分:0)
该方法确实存在。表单关闭的事实不会改变类或其方法。如果您发布了您所获得的确切异常,它可以帮助某人提供更准确的帮助。
我猜你在表单或其控件关闭后尝试对表单执行某些操作时会得到ObjectDisposedException
。
如果是这种情况,您只需要在调用SetGridDataSource之前增强逻辑并检查表单是否已关闭或处理。
也就是说,您的设计似乎存在一些问题。
EndInvoke
上致电BeginInvoke
。BackgroundWorker
的内容而不是链接BeginInvoke
来电。catch
是一个非常糟糕的主意,并通过在不重新抛出的情况下忽略它来处理任何抛出的异常。顺便说一句,而不是这样做:
BeginInvoke(new Action<List<ds>>(SetGridDataSource), dataSource);
您可以执行以下操作,我认为这些内容更具可读性:
BeginInvoke(SetGridDataSource, dataSource);