Reputation: 8336
I have Selected objects DataGrid whose row selection changed is handled in method (using interactrion event trigger InvokeCommandAction). A row represents a real life object and has lots of properties.
I first set an property that row corresponds and highlight object on map, do some other stuff and finally call async a method that fetches object properties and refreshes property DataGrid with those properties.
SelectedObjectsViewModel.cs (Viewmodel for UserControl containing SelectedObjects DataGrid)
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 (Viewmodel for UserControl containing Properties DataGrid)
// 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;
}
}
}
However there's up to 1,2 second delay for DataGrid containing object properties to be refreshed after everything else like highlighting is done. I would like to start fetching immediately i know the object, proceed with highlighting etc and finally have asynchronously started SelectedObjectsChanged to use the fetched property data just to refresh DataGrid.
Fetching involves both database fetch and some processing. Depending on circumstances and settings the database fetch time can be up to 80%, but it can be only 50%.
My question is: How this should be done so that:
Thanks!
Upvotes: 2
Views: 1131
Reputation: 169420
You should execute any long-running method on a background thread. Note that you cannot access any UI elements on a background thread though, so you basically need to start a new task that fetches the data, and then handle any UI stuff once the task completes.
Here is a basic sample that executes the GetAttributeObjectAttributes()
method on a background thread:
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());
}
Note that the ObjectViewModel
class should implement the INotifyPropertyChanged interface and raise the PropertyChanged
event whenever the data-bound ObjectInfoItems
property is set.
Edit:
Another example based on your comments:
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());
}
Upvotes: 4