2017-09-26 26 views
2

我有选择的对象DataGrid的行选择更改是在方法中处理(使用Interactrion事件触发器InvokeCommandAction)。一行表示一个真实的生活对象,并有很多属性。如何在后台获取数据并在准备好后用数据异步更新UI?

我首先设置一个属性,该行对应并在地图上高亮显示对象,做一些其他的东西,最后调用异步方法来获取对象属性并使用这些属性刷新属性DataGrid。

SelectedObjectsViewModel.cs(视图模型包含的selectedObjects数据网格用户控件)

public void SelectedObjectsGridSelectionChangedCommand(object parameter) 
{ 
    IList selectedRows = parameter as IList; 
    if (selectedRows.Count == 1) 
     ObjectProperties.Instance.SetAttributeObjectNoRefresh(((SelectedNetObjectBindingSource)selectedRows[0]).Data); 
    else       
     ObjectProperties.Instance.SetAttributeObjectNoRefresh(null); 

    SetAttributeObjectExtraHightlight<SelectedNetObjectBindingSource>(selectedRows); 

    DoSomeOtherStuff(selectedRows) 

    App.Current.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, (Action)(() => 
    { 
     ((ObjectViewModel)MyApp.ViewModels["Shared.Panels.Object"]).SelectedObjectsChanged(); 
    })); 
} 

ObjectViewModel.cs(视图模型包含属性数据网格用户控件)

// this is ItemsSource binding for properties datagrid 
    public ICollectionView ObjectInfoItems { get; private set; } 

    public ObjectViewModel() 
    { 
     ObjectInfoItems = CollectionViewSource.GetDefaultView(ObjectProperties.Instance.GetAttributeObjectAttributes()); 
    } 

    public void SelectedObjectsChanged() 
    { 
     // refreshed DataGrid 
     ObjectInfoItems.Refresh(); 
    } 

ObjectProperties.cs

public void SetAttributeObjectNoRefresh(NetObject netObject) 
    { 
     _attributeObject = netObject; 
    } 

    public IEnumerable<PropertyRow> GetAttributeObjectAttributes() 
    { 
     if (_attributeObject != null) 
     { 
      List<string> fieldNames = new List<string>(); 
      List<string> visibleNames = new List<string>(); 
      List<string> values = new List<string>(); 
      /* get properties for _attributeObject from db and 
      * process in native code */ 
      var properties = GetPropertiesFilterAndSort(fieldNames, visibleNames, values, _attributeObject); 

      foreach (var property in properties) 
      { 
       yield return property; 
      } 
     } 
    } 

但是,Dat有最多1,2秒的延迟一个包含对象属性的aGrid,在完成其他所有事情之后将被刷新。我想开始立即获取我知道的对象,继续突出显示等,最后异步启动SelectedObjectsChanged使用获取的属性数据只是刷新DataGrid。

提取包括数据库提取和一些处理。取决于环境和设置,数据库获取时间可能高达80%,但只能达到50%。

我的问题是:这个应该怎么做,这样:

  1. 在选定对象的DataGrid行选择,并强调在地图上立即着手在所有
  2. 没有等待财产取或财产的DataGrid刷新所选对象datagrid选择后的属性DataGrid刷新没有很长的延迟,因为它正在获取属性

谢谢!

+0

[Binding.IsAsync](https://msdn.microsoft.com/en-us/library/system.windows .data.binding.isasync(v = vs.110).aspx)? – Sinatr

+0

@Sinatr:我认为这和现在一样有效。所有发生在UI线程?我需要另一个线程来获取数据。 –

+0

那么你在哪里获取数据?在后台线程上调用此方法... – mm8

回答

3

您应该在后台线程上执行任何长时间运行的方法。请注意,您不能访问后台线程上的任何UI元素,因此您基本上需要开始一项新任务来获取数据,然后在任务完成后处理任何UI内容。

这里是执行GetAttributeObjectAttributes()方法在后台线程一个基本的例子:

private ICollectionView _ojectInfoItems; 
public ICollectionView ObjectInfoItems 
{ 
    get { return myVar; } 
    set { myVar = value; OnPropertyChanged(); } 
} 

public ObjectViewModel() 
{ 
    Task.Factory.StartNew(() => 
    { 
     return ObjectProperties.Instance.GetAttributeObjectAttributes(); 
    }).ContinueWith(task => 
    { 
     ObjectInfoItems = CollectionViewSource.GetDefaultView(task.Result); 
    }, System.Threading.CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext()); 
} 

注意,ObjectViewModel类应实现INotifyPropertyChanged接口,并且每当数据绑定ObjectInfoItems属性设置提高PropertyChanged事件。

编辑:

又如根据您的意见:

public void SelectedObjectsGridSelectionChangedCommand(object parameter) 
{ 
    object data = null; 
    IList selectedRows = parameter as IList; 
    if (selectedRows.Count == 1) 
     data = (SelectedNetObjectBindingSource)selectedRows[0]).Data; 

    Task.Factory.StartNew(() => 
    { 
     ObjectProperties.Instance.SetAttributeObjectNoRefresh(null); 

     Parallel.Invoke(
      () => SetAttributeObjectExtraHightlight<SelectedNetObjectBindingSource>(selectedRows), 
      () => DoSomeOtherStuff(selectedRows)); 

    }).ContinueWith(task => 
    { 
     ((ObjectViewModel)MyApp.ViewModels["Shared.Panels.Object"]).SelectedObjectsChanged(); 
    }, System.Threading.CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext()); 
} 
+0

@ mm8:这应该发生在SelectedObjectsGridSelectionChangedCommand中(请参阅问题),我希望启动后台线程,然后执行SetAttributeObjectExtraHightlight和DoSomeOtherStuff,当后台线程返回并且结果DataGrid刷新异步执行时,UI将会响应。现在我不知道如何执行这两个方法,导致后台线程继续刷新。这ContinueWith非常酷,否则。 –

+3

请注意,推荐的启动任务的方式是Task.Run(自.NET 4.5起)。建议只在绝对必要时才使用'Task.Factory.StartNew',参见[这篇伟大的博客文章](http://blog.stephencleary.com/2013/08/startnew-is-dangerous.html)。 – dymanoid

+0

@matti:我不明白。任务中的所有代码都在后台线程上运行,而ContinueWith中的所有代码在UI线程上运行。 – mm8