问题
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?
回答1:
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));
}
}
回答2:
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