C#I';我从任务或调度程序获取null
我有以下代码:C#I';我从任务或调度程序获取null,c#,.net,multithreading,asynchronous,dispatcher,C#,.net,Multithreading,Asynchronous,Dispatcher,我有以下代码: public void OpenReport(XtraReport report, int zoomMode) { //Show loading animation. MainInterfaceViewModel.State = States.Busy; //Load the report, then navigate to the ReportViewer Task tsk = Task.Factory.S
public void OpenReport(XtraReport report, int zoomMode)
{
//Show loading animation.
MainInterfaceViewModel.State = States.Busy;
//Load the report, then navigate to the ReportViewer
Task tsk = Task.Factory.StartNew(() => LoadReport(report, zoomMode));
//After completing the task hide the loading animation
tsk.ContinueWith(obj => MainInterfaceViewModel.State = States.Idle);
}
private void LoadReport(XtraReport report, int zoomMode)
{
ReportViewerViewModel reportViewerViewModel;
reportViewerViewModel = new ReportViewerViewModel(report, zoomMode);
ReportViewer.Dispatcher.Invoke(new Action(() => ReportViewer.DataContext = reportViewerViewModel)) ;
Frame.Navigate(ReportViewer);
}
但是当执行OpenReport方法时,我得到一个空的ReportViewer,为什么在我将报告传递给该方法时会出现这个问题?
下图显示了我得到的结果
编辑:
当我将OpenReport方法更改为以下代码时,我会在报表查看器中显示报表,但在准备报表时UI会冻结(大约3秒)
正如@TotaloDotoNeto试图指出的那样,
Task.StartNew
有时使用起来很危险,因为它使用了TaskScheduler.Current
而不是TaskScheduler.Default
属性,这很难处理。斯蒂芬·克利里有,如果你感兴趣,这里是。因此,首先我建议您切换到Run
方法:
Task tsk = Task.Run(() => LoadReport(report, zoomMode));
其次,让我们看看您的代码在做什么:启动一个任务
,在该任务中使用一些后台逻辑(Dispatcher.Invoke
)和前台逻辑(Frame.Navigate
)。我认为您遇到的问题是由于Frame
的代码不是在UI线程中执行的。因此,您有两种选择:
// add the Navigate method to the invoking delegate
ReportViewer.Dispatcher.Invoke(new Action(() =>
{
ReportViewer.DataContext = reportViewerViewModel;
Frame.Navigate(ReportViewer);
}));
或者使您的代码异步
,如下所示:
public async Task OpenReport(XtraReport report, int zoomMode)
{
// Show loading animation.
MainInterfaceViewModel.State = States.Busy;
// Asynchronously wait for the model to load
var task = await Task.Run(() => LoadReport(report, zoomMode));
// process the model after it's being loaded
ReportViewer.DataContext = task.Result;
// Navigate to the ReportViewer
Frame.Navigate(ReportViewer);
// After completing the task hide the loading animation
MainInterfaceViewModel.State = States.Idle;
}
private async Task<ReportViewerViewModel> LoadReport(XtraReport report, int zoomMode)
{
return new ReportViewerViewModel(report, zoomMode);
}
public异步任务OpenReport(XtraReport报告,int zoomMode)
{
//显示加载动画。
MainInterfaceViewModel.State=状态忙;
//异步等待模型加载
var task=wait task.Run(()=>LoadReport(report,zoomMode));
//加载模型后对其进行处理
ReportViewer.DataContext=task.Result;
//导航到ReportViewer
框架导航(ReportViewer);
//完成任务后,隐藏加载动画
MainInterfaceViewModel.State=States.Idle;
}
专用异步任务加载报告(XtraReport,int zoomMode)
{
返回新的ReportViewerViewModel(报告、zoomMode);
}
注意,在第二种情况下,您必须重写代码。如果您对此主题感兴趣,请参阅一些有用的文章。正如@TotaloDotoNeto试图指出的,
Task.StartNew
有时使用是危险的方法,因为它使用的是TaskScheduler.Current
而不是TaskScheduler.Default
属性,这很难处理。斯蒂芬·克利里有,如果你感兴趣,这里是。因此,首先我建议您切换到Run
方法:
Task tsk = Task.Run(() => LoadReport(report, zoomMode));
其次,让我们看看您的代码在做什么:启动一个任务
,在该任务中使用一些后台逻辑(Dispatcher.Invoke
)和前台逻辑(Frame.Navigate
)。我认为您遇到的问题是由于Frame
的代码不是在UI线程中执行的。因此,您有两种选择:
// add the Navigate method to the invoking delegate
ReportViewer.Dispatcher.Invoke(new Action(() =>
{
ReportViewer.DataContext = reportViewerViewModel;
Frame.Navigate(ReportViewer);
}));
或者使您的代码异步
,如下所示:
public async Task OpenReport(XtraReport report, int zoomMode)
{
// Show loading animation.
MainInterfaceViewModel.State = States.Busy;
// Asynchronously wait for the model to load
var task = await Task.Run(() => LoadReport(report, zoomMode));
// process the model after it's being loaded
ReportViewer.DataContext = task.Result;
// Navigate to the ReportViewer
Frame.Navigate(ReportViewer);
// After completing the task hide the loading animation
MainInterfaceViewModel.State = States.Idle;
}
private async Task<ReportViewerViewModel> LoadReport(XtraReport report, int zoomMode)
{
return new ReportViewerViewModel(report, zoomMode);
}
public异步任务OpenReport(XtraReport报告,int zoomMode)
{
//显示加载动画。
MainInterfaceViewModel.State=状态忙;
//异步等待模型加载
var task=wait task.Run(()=>LoadReport(report,zoomMode));
//加载模型后对其进行处理
ReportViewer.DataContext=task.Result;
//导航到ReportViewer
框架导航(ReportViewer);
//完成任务后,隐藏加载动画
MainInterfaceViewModel.State=States.Idle;
}
专用异步任务加载报告(XtraReport,int zoomMode)
{
返回新的ReportViewerViewModel(报告、zoomMode);
}
注意,在第二种情况下,您必须重写代码。如果你对这个主题感兴趣的话,还有一些关于如何做的有用文章。报告来自哪里?报告来自另一个类上的方法,我在没有任务和调度程序的情况下尝试了所有这些,它正在工作,但速度非常慢,UI冻结了很多。不清楚您仅通过从另一个线程/任务执行Dispatch.Invoke()来尝试实现什么。我正在尝试通过将报告加载到名为ReportViewer的报告查看器上,然后通过:Frame.navigate(ReportViewer)导航到该报告查看器;我建议使用Task.Run而不是Task.Factory.StartNew。因为根据MSDN博客。Task.Factory.StartNew并没有完全脱口而出,至少对于在诸如轻松将工作转移到后台处理线程之类的主要场景中使用的某些东西来说还不够快。请仔细阅读以下内容,如
report
从何而来?该报告来自另一个类上的方法,我在没有任务和调度程序的情况下尝试了所有这些,但运行非常缓慢,UI冻结了很多。不清楚您仅通过执行Dispatch.Invoke()来尝试实现什么从另一个线程/任务。我正在尝试通过将报告加载到名为ReportViewer的报告查看器上,然后通过以下方式导航到报告查看器:Frame.navigate(ReportViewer);我建议使用Task.Run而不是Task.Factory.StartNew。因为根据MSDN博客。Task.Factory.StartNew并没有完全脱口而出,至少对于在诸如轻松将工作转移到后台处理线程之类的主要场景中使用的某些东西来说还不够快。请看下面的例子谢谢你的回答,但是这两个选项都不起作用,我得到的结果是一样的。当我使用同步代码时,报告在前面的UI冻结中显示正常,但我得到一个带有异步代码的空白ReportViewer。有点不对劲,但到底是什么?我觉得自己很傻。你的导航呼叫在哪里?我认为问题在于它是在您获得数据源之前执行的。你能提供你尝试过的代码吗?我上一个问题“编辑”中的代码可以工作,但UI冻结,而你提供的代码不工作,我得到一个空白的ReportViewer。你是否签入调试任务中返回的内容。结果
?是的,它返回一个ReportViewer