I’m new to asynchronous processing in .net (honestly to .net at all) and need help with the following problem.
To bring it to the point, I need to know how to handle multiple calls of a synchronized method.
I got the following C# MVVM application:
Both Datagrids are binded to a Viewmodel. The First Datagrid is the input for the second. Every time a checkbox in the first Datagrid is clicked, a DelegateCommand is triggered, to refresh the content of the second datagrid.
The refreshment works like in this example:
<DataGrid AutoGenerateColumns="False"
ItemsSource="{Binding Path=Datagrid1}" >
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Boolean, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Command="{Binding DataContext.CheckBoxDataGrid1Click, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
ObservableCollection<string> col1 = ObservableCollection<string>();
ObservableCollection<string> col2 = ObservableCollection<string>();
DelegateCommand CheckBoxDataGrid1Click = new DelegateCommand(CheckBoxDataGrid1ClickExecute);
// Needs to be async, so that the UI thread is will not be freezed.
private async void CheckBoxDataGrid1ClickExecute()
{
var ui = TaskScheduler.FromCurrentSynchronizationContext();
await Task.Factory.StartNew(
() =>
{
return getNewObjects();
}).ContinueWith(t =>
{
col2 = t.Result;
}, ui);
}
[MethodImpl(MethodImplOptions.Synchronized)]
public ObservableCollection<string> getNewObjects()
{
// Here is a long processing SQL Query
// So lets wait a few seconds
Thread.Sleep(5000);
// return dummy in this example
return new ObservableCollection<string>();
}
I got problems, if someone click a checkbox (in Datagrid1), when the processing of the last click has not finished.
My first idea was to make the getNewObjects() method synchronized. This solved a few problems. But, multiple clicks cause now a queue of refreshments. On the one hand I don’t know the sequence of the calls. On the other hand I’m just interested in the result of the last click.
The second idea was to modify the getNewObjects() method, so that it can be cancelled by CancellationToken. (I already started a question here - C# Synchronized Method call kills current processing). This way does not work too. The method contains a SQL query which cannot be cancelled easily in this case. I’m not able to modify the execution of the query or the SqlCommand.
To sum up: Is there a way to discard the current processing of the refreshment and start the new one? If not, how can I handle the Queue of calls? I need to make sure, that the last call will be the content of the second Datagrid, even if there is another one finishing later.
I'm open to any advise to solve tis problem. Maybe there is a better way of refreshing this second Datagrid, everytime Datagrid 1 has changed.