Dispatcher: abort dispatcher operation

*爱你&永不变心* 提交于 2019-12-06 13:29:58

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!