2017-09-26 74 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