UWP如何从任务中更新UI

20

我有一个应用程序,它在本地网络中检查网络范围(以运行http服务)。

这意味着,我正在检查例如从10.0.0.1到10.0.0.255。然而问题是,当在PC上运行时速度足够,但是当在Lumia 950上运行时速度不够。因此,我想在扫描过程中更新UI。

所以这里有几个问题:

  1. 目前我有几个任务,例如10个-每个任务都在扫描其范围,例如任务1-10.0.0.1到10.0.0.25等-我应该使用10个任务还是有某种方式可以由.net自己解决?如果我使用50个任务性能会如何?

  2. 第二个问题是,在扫描期间,我将找到正在工作的Web服务的PC,但是......当找到PC时,应该如何更新UI?目前我只能在所有任务完成时才能这样做。

我调用的方法是异步任务

3个回答

52
  1. 您可以使用尽可能多的任务,系统会自动为您执行排队和执行。这是使用内置机制的优点之一。

  2. 要在UI线程上执行代码,您可以像这样使用dispatcher:

  3. await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => {
                //UI code here
    });
    

你好,感谢回答。看起来它正在工作。但是还有其他要求...例如,如果一个线程找到了服务器,我应该将其添加到ListBox中,有没有什么解决方法? - petrtim
很高兴听到这篇文章对您有所帮助。您可以考虑将其标记为答案,以便其他人可以轻松地找到它。至于其他需求,那应该是一个单独的问题。请尝试提供一些您已经尝试过的示例代码,以便人们知道从哪里开始提供答案。 - AlexDrenea
1
调度程序没有 RunAsync 方法? - ShrimpCrackers
你如何防止出现以下错误:“当前上下文中不存在调度程序名称”? - Doug Null
1
你应该编写 Window.Current.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High, () = > {});。 - Luis Alves

22

如果你想在UI线程上执行代码,并且只想更新属性,那么可以使用MVVM和ViewModel继承该类。

public abstract class NotifyPropertyChangedBase : INotifyPropertyChanged
{
   public event PropertyChangedEventHandler PropertyChanged;

   protected async void OnPropertyChanged([CallerMemberName] string propName = "")
   {
       await Window.Current.Dispatcher.RunAsync(CoreDispatcherPriority.High,
           () =>
           {
               PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
           });
   }
}

所有在 Xaml 数据绑定中使用的属性都可以是单向或双向的,属性中需要使用 OnPropertyChanged() 方法。如果我的代码出现异常并报告“Current 为空”,你可以使用

await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => 
{
     //write your code
     //in OnPropertyChanged use PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
});
如果您在用户控件或可见以下代码的页面中编写了代码。
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => 
{
            //UI code here
});

CoreDispatcherPriority可以设置优先级,但不应将其设置为高优先级,请参见CoreDispatcherPriority


你好,看起来很有趣,我部分地使用了你的方法。但问题是,从类中更新GUI好吗?我认为这不太干净..也许还有其他解决方案? - petrtim
如果你绑定了,它就会被更新。有一些,我没有链接。 - lindexi
所以最终我使用了这个解决方案,并且它起作用了。 链接 - petrtim
如果您更改了属性,但UI没有发生变化。因此最终您也应该像我一样使用代码。链接(http://www.c-sharpcorner.com/UploadFile/5ef5aa/binding-collection-to-listview-control-in-uwp-explained/)可以更改列表但不能更改属性。 - lindexi
是的,但在我的情况下,属性是List<string>,因此即使向列表添加了某些内容,事件也不会被触发。 - petrtim
1
使用ObservableCollection,它可以在添加或删除项时进行通知。 - lindexi

-2
我还发现另一个更新用户界面的可能性 - 目前我是通过这种方式更新进度条,但发现你可以传递其他变量。。
 var progress = new Progress<int>(i => _progress = i);
 progress.ProgressChanged += Pr_ProgressChanged;

然后事件:

  private void Pr_ProgressChanged(object sender, int e)
    {
        progressBar1.Value = progressBar1.Value + 1;
    }

带参数的方法:

 public async Task GetWebServers(IProgress<int> progress) {
 //your code
}

调用:

await Task.WhenAll(workers.Select(webServer => webServer.GetWebServers(progress))
       );

1
这在某些情况下可能有效,但是如果要从异步任务中调用UI(可以从其他线程调用),最好使用Dispatcher。 - Benoit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接