当前位置: 首页 > 编程语言 > C#

WinRT-在保持UI响应的同时加载数据

时间:2023-04-10 21:30:16 C#

WinRT-在保持UI响应的同时加载数据我正在开发一个WindowsMetro应用程序,但我遇到了UI没有响应的问题。据我所知,原因如下:this.InvalidateVisualState();MyDataItemdataItem=e.AddedItems[0]asMyDataItem;等待LoadMyPage(数据项);}privateasyncTaskLoadMyPage(MyDataItemdataItem){SyndicationClientclient=newSyndicationClient();));stringhtml=ConvertRSSToHtml(feed)myWebView.NavigateToString(html,true);LoadMyPage需要一段时间才能完成,因为它从Web服务获取数据并将其加载到屏幕上。但是,看起来UI正在等待它:我的猜测是,直到上述事件完成。所以我的问题是:我能做些什么呢?有没有更好的事件我可以挂钩,或者有另一种方法来处理这个问题?我考虑过启动后台任务,但这对我来说似乎有点矫枉过正。编辑:为了澄清问题的严重性,我说的是最多3到4秒的无响应。这绝不是一项长期工作。编辑:我已经尝试了下面的一些建议,但是,SelectionChanged函数中的整个调用堆栈都在使用async/await。我已经找到了这条线:myFeed=awaitclient.RetrieveFeedAsync(uri);在完成之前似乎不会继续处理。编辑:我意识到这正在变成战争与和平,但这里是如何使用空白地铁应用程序和按钮复制问题:XAML:testCodeBehind:privateasyncvoidButton_Click_1(objectsender,RoutedEventArgse){SyndicationFeedfeed=null;SyndicationClient客户端=newSyndicationClient();UrifeedUri=newUri(myUri);尝试{feed=awaitclient.RetrieveFeedAsync(feedUri);foreach(variteminfeed.Items){test.Text+=item.Summary.Text+Environment.NewLine;}}catch{test.Text+="连接失败";}}试一试...SyndicationFeedfeed=null;SyndicationClient客户端=newSyndicationClient();varfeedUri=newUri(myUri);尝试{vartask=client.RetrieveFeedAsync(feedUri).AsTask();task.ContinueWith((x)=>{varresult=x.Result;Parallel.ForEach(result.Items,item=>{Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,()=>{测试。文本+=item.Title.Text;});});});}catch(Exceptionex){}在我的机器上,我正在尝试使用Grid应用程序模板来应用程序添加按钮。在更新页面标题时,我可以毫无问题地来回滚动项目网格。虽然我没有很多东西,但进展很快,所以很难100%肯定。由于您在LoadMyPage前面使用await,我假设它编译并返回一个任务。鉴于此,我创建了一个小示例。让我们假设LoadMyPage(和Sleep())看起来像这样:}staticvoidSleep(intms){newManualResetEvent(false).WaitOne(ms);XAML看起来像这样:TestTest2SomeButtonSomeButton2然后我们可以使SelectionChanged事件处理程序看起来像这样:varresult=awaitLoadMyPage();结果.Text=结果;我的列表.IsEnabled=true;LoadMyPage返回的Task将并行运行,这意味着当任务运行时,UI不应冻结。现在,要从此任务获取结果,请使用await。这将创建一个延续块。所以在这个例子中,当你选择一些东西时,ListView将在整个加载时间内被禁用,然后在任务完成后重新启用。您可以通过按下按钮以确保它仍然响应来确认UI没有冻结。如果LoadMyPage与UI交互,您需要重新排列它以便它返回ViewModel或您想要的任何内容,然后再次将所有内容放在UI线程上。后台线程绝对不过分。这正是您处理此类问题的方式。不要在UI线程上执行冗长的任务,否则您会占用UI并使其无响应。在后台线程上运行它们,然后让该线程引发一个事件,该事件完成后可由主UI线程处理。在UI线程上显示某种进度指示器也很有用。用户喜欢知道发生了什么。这会让他们放心,应用程序没有损坏或冻结,他们愿意等待一段时间。这就是为什么所有网络浏览器都有某种“悸动”或其他加载指示器。最可能的问题是LoadMyPage正在同步执行某些操作。请记住,异步不会在后台线程上运行您的代码;默认情况下,它的所有实际代码都将在UI线程上运行(请参阅async/awaitFAQ或我的async/awaitintro)。因此,如果您阻塞异步方法,它仍会阻塞调用线程。查看LoadMyPage。您是否正在使用await来调用网络服务?在将数据放入UI之前是否进行了昂贵的数据处理?它是否使UI不堪重负(许多Windows控件在获取数千个元素时存在可伸缩性问题)?查看您的简化代码示例,我相信您的问题是位于await行之外的内容。在以下代码块中:privateasyncvoidButton_Click_1(objectsender,RoutedEventArgse){SyndicationFeedfeed=null;SyndicationClient客户端=newSyndicationClient();UrifeedUri=newUri(myUri);尝试{feed=awaitclient.RetrieveFeedUri();foreach(variteminfeed.Items){test.Text+=item.Summary.Text+Environment.NewLine;}}catch{test.Text+="连接失败";该行是行feed=awaitclient.RetrieveFeedAsync(feedUri);此块中的所有其他代码行都在UI线程上执行。仅仅因为您的按钮单击处理程序被标记为异步并不意味着其中的代码不会在UI线程上运行。事实上,事件处理程序是在UI线程上启动的。因此创建SyndicationClient和设置Uri发生在UI线程上。许多开发人员没有意识到的是,在await之后进入的任何代码都会自动在await之前使用的同一线程上恢复。这意味着代码foreach(variteminfeed.Items){test.Text+=item.Summary.Text+Environment.NewLine;}正在UI线程上运行!这很方便,因为您不必执行Dispatcher.Invoke来更新test.Text,但这也意味着您在循环遍历项目和连接字符串时阻塞了UI线程。在您的(尽管已简化)示例中,在后台线程上执行此工作的最简单方法是在SyndicationClient上使用另一种方法,称为RetrieveFeedAsStringAsync;SyndicationClient然后可以将字符串的下载、循环和连接作为其自身任务的一部分。该任务完成后,将在UI线程上运行的唯一代码行将文本分配给TextBox。以上就是C#学习教程:WinRT——加载数据共享的所有内容同时保持UI响应。如果对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场,如涉及侵权,请点击右边联系管理员删除。如需转载请注明出处: