Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 187 Vote(s) - 3.55 Average
  • 1
  • 2
  • 3
  • 4
  • 5
This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread

#1
I have a DataGrid which is populating data from ViewModel by asynchronous method.My DataGrid is :


<DataGrid ItemsSource="{Binding MatchObsCollection}" x:Name="dataGridParent"
Style="{StaticResource EfesDataGridStyle}"
HorizontalGridLinesBrush="#DADADA" VerticalGridLinesBrush="#DADADA" Cursor="Hand" AutoGenerateColumns="False"
RowDetailsVisibilityMode="Visible" >

I am using

[To see links please register here]

to implement asynchronous way in my viewmodel.

Here is my viewmodel code:

public class MainWindowViewModel:WorkspaceViewModel,INotifyCollectionChanged
{

MatchBLL matchBLL = new MatchBLL();
EfesBetServiceReference.EfesBetClient proxy = new EfesBetClient();

public ICommand DoSomethingCommand { get; set; }
public MainWindowViewModel()
{
DoSomethingCommand = new AsyncDelegateCommand(
() => Load(), null, null,
(ex) => Debug.WriteLine(ex.Message));
_matchObsCollection = new ObservableCollection<EfesBet.DataContract.GetMatchDetailsDC>();

}

List<EfesBet.DataContract.GetMatchDetailsDC> matchList;
ObservableCollection<EfesBet.DataContract.GetMatchDetailsDC> _matchObsCollection;

public ObservableCollection<EfesBet.DataContract.GetMatchDetailsDC> MatchObsCollection
{
get { return _matchObsCollection; }
set
{
_matchObsCollection = value;
OnPropertyChanged("MatchObsCollection");
}
}
//
public void Load()
{
matchList = new List<GetMatchDetailsDC>();
matchList = proxy.GetMatch().ToList();

foreach (EfesBet.DataContract.GetMatchDetailsDC match in matchList)
{
_matchObsCollection.Add(match);
}

}

As you can see in my Load() method in my ViewModel first I am getting matchList (which is a list of a DataContract Class) from my Service.Then by foreach loop I am inserting my matchList items to my _matchObsCollection(which is an ObservableCollection of DataContract Class)).Now here I am getting the above error (as I shown in Title) "This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread"
![enter image description here][1]


[1]:


Can anyone suggest me any solution.Moreover if possible I would like to know how to bind my DataGrid in View and also refresh it asynchronously if any better way is there.
Reply

#2
If I'm not mistaken, in WPF 4.5, you should be able to do this without any problem.

Now to solve this, you should use the synchronization context. Before you launch the thread, you have to store the synchronization context in the ui thread.

var uiContext = SynchronizationContext.Current;

Then you use it in your thread:

uiContext.Send(x => _matchObsCollection.Add(match), null);

Take a look at this tuto
[

[To see links please register here]

][1]


[1]:

[To see links please register here]

Reply

#3
Since your ObservableCollection is created on UI thread, you can only modify it from UI thread and not from other threads. This is termed as [thread affinity][1].

If you ever need to update objects created on UI thread from different thread, simply `put the delegate on UI Dispatcher` and that will do work for you delegating it to UI thread. This will work -

public void Load()
{
matchList = new List<GetMatchDetailsDC>();
matchList = proxy.GetMatch().ToList();

foreach (EfesBet.DataContract.GetMatchDetailsDC match in matchList)
{
App.Current.Dispatcher.Invoke((Action)delegate // <--- HERE
{
_matchObsCollection.Add(match);
});
}
}


[1]:

[To see links please register here]

Reply

#4
I have experienced the same issue once and resolved the issue with AsyncObservableCollection (

[To see links please register here]

).
Reply

#5
In my case (I populate `ObservableCollection` with asynchronous tasks and do not have access to `App` instance) I use `TaskScheduler.FromCurrentSynchronizationContext()` to cleanup the collection on faulted:

// some main task
Task loadFileTask = Task.Factory.StartNew(...);

Task cleanupTask = loadFileTask.ContinueWith(
(antecedent) => { CleanupFileList(); },
/* do not cancel this task */
CancellationToken.None,
/* run only if faulted main task */
TaskContinuationOptions.OnlyOnFaulted,
/* use main SynchronizationContext */
TaskScheduler.FromCurrentSynchronizationContext());
Reply

#6
If you are using BackgroundWorker you should **raise the event** in the same thread of the UI.

For i.e. if you have two views A and B and the following code inside A raises the event WakeUpEvent

//Code inside codebehind or viewmodel of A
var worker = new BackgroundWorker();
worker.DoWork += WorkerDoWork; //<-- Don't raise the event WakeUpEvent inside this method
worker.RunWorkerCompleted += workerRunWorkerCompleted; // <-- Raise the event WakeUpEvent inside this method instead
worker.RunWorkerAsync();

//Code inside codebehind or viewmodel of view B
public ViewB () {
WakeUpEvent += UpdateUICallBack;
}
private void UpdateUICallBack() {
//Update here UI element
}

The WorkerDoWork method is executed in a thread that is not the same of the UI.
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through