I want adding items to DataGrid in thread.
I have view model for my user control:
public class Contact
{
public string Name { get; set; }
public string Phone { get; set; }
}
public class ContactGridViewModel
{
public ContactGridViewModel()
{
Items = new ObservableCollection<Contact>();
}
public ObservableCollection<Contact> Items { get; private set; }
public Dispatcher Dispatcher
{
get { return Dispatcher.CurrentDispatcher); }
}
private DispatcherOperation LastOperation { get; set; }
public void Update(IEnumerable<Contact> contacts)
{
if (LastOperation != null) LastOperation.Abort();
Items.Clear();
foreach (var item in contacts)
LastOperation = Dispatcher.BeginInvoke(
DispatcherPriority.Background,
new ParameterizedThreadStart(o => Items.Add(o))),
item);
}
}
There is the markup example:
<!--DataContext="{Binding ContactGridViewModel}-->
<DataGrid ItemsSource="{Binding Items, Mode=OneWay}">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Path=Name}" />
<DataGridTextColumn Header="Phone" Binding="{Binding Path=Phone}" />
</DataGrid.Columns>
</DataGrid>
After Update method is executed second time, and if first collection is not completely added, DataGrid will contains part of first collection and full second collection.
// contactList1 and contactList2 are IEnumerable<Contact> objects
Model.Update(contactList1);
Model.Update(contactList2);
I try to abort DispatcherOperation, but it's not stop adding contacts into Items property.
Could you tell me the correct method of adding objects to DataGrid ItemsSource?
You should collect all DispatcherOpretations in list and then abort them all.
public class ContactGridViewModel
{
public ContactGridViewModel()
{
Items = new ObservableCollection<Contact>();
LastOperations = new List<DispatcherOperation>();
}
public ObservableCollection<Contact> Items { get; private set; }
private ICollection<DispatcherOperation> LastOperations { get; set; }
public Dispatcher Dispatcher
{
get { return Dispatcher.CurrentDispatcher); }
}
private void StopUpdating()
{
foreach (var operation in LastOperations)
{
operation.Abort();
}
LastOperations.Clear();
}
public void Update(IEnumerable<Contact> contacts)
{
StopUpdating();
Items.Clear();
foreach (var item in contacts)
LastOperations.Add(Dispatcher.BeginInvoke(
DispatcherPriority.Background,
new ParameterizedThreadStart(o => Items.Add(item))),
item));
}
}
In your Update(contactList1)
method you start a Dispatcher.BeginInvoke()
for every item in contactList1, but if you enter Update(contactList2)
you abort only once the LastOperation, which is not the complete foreach but an single Items.Add()
.
Try something like this (not tested):
public void Update(IEnumerable<Contact> contacts)
{
if (LastOperation != null) LastOperation.Abort();
Items.Clear();
LastOperation = Dispatcher.BeginInvoke(
DispatcherPriority.Background,
new ParameterizedThreadStart(o => { foreach (var item in o) Items.Add(item); }),
contacts);
}
来源:https://stackoverflow.com/questions/10334497/dispatcher-abort-dispatcher-operation