I am making a file transfer program. The user can add as many file transfers (both download/upload), and those will go in FIFO order. The first choice would be to use a Queue<T>
. The problem here is the fact that unlike ObservableCollection
, it does not automatically reflect the changes in the UI. I have a ListView
control which has the source set to what is currently the Queue<T>
, and after doing Enqueue() the UI does not update.
Is my best/only option just to use the ObservableCollection
like a Queue
, such as removing the first item after a file transfer is complete?
public async void ExecuteRequestDownloadCommand(object commandParameter)
{
if (!(commandParameter is ModularPacket packet))
{
return;
}
foreach (FileTransferModel transfer in this.ModularPacketManager.DownloadRequest(packet))
{
FileTransferQueue.Enqueue(transfer);
}
}
<ListView x:Name="FileTransferListView" ItemsSource= "{Binding FileTransferQueue}">
<ListView.View>
<GridView>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" Width="Auto"/>
<GridViewColumn Header="Type" DisplayMemberBinding="{Binding Type}" Width="Auto"/>
<GridViewColumn Header="Size" DisplayMemberBinding="{Binding Size}" Width="Auto"/>
<GridViewColumn Header="Progress" DisplayMemberBinding="{Binding Progress}" Width="Auto"/>
</GridView>
</ListView.View>
</ListView>
CodePudding user response:
The complexity of Queue<T>.Dequeue
is O(1) where Collection<T>.RemoveAt
is O(n). This makes using a native Queue<T>
the better option. You can extend Queue<T>
to add collection changed notifications.
You can use the following implementation:
public class ObservableQueue<TItem> : Queue<TItem>, INotifyCollectionChanged, INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
public event NotifyCollectionChangedEventHandler? CollectionChanged;
new public void Enqueue(TItem item)
{
base.Enqueue(item);
OnPropertyChanged();
OnCollectionChanged(NotifyCollectionChangedAction.Add, item, this.Count - 1);
}
new public TItem Dequeue()
{
TItem removedItem = base.Dequeue();
OnPropertyChanged();
OnCollectionChanged(NotifyCollectionChangedAction.Remove, removedItem, 0);
return removedItem;
}
new public bool TryDequeue(out TItem? result)
{
if (base.TryDequeue(out result))
{
OnPropertyChanged();
OnCollectionChanged(NotifyCollectionChangedAction.Remove, result, 0);
return true;
}
return false;
}
new public void Clear()
{
base.Clear();
OnPropertyChanged();
OnCollectionChangedReset();
}
private void OnCollectionChanged(NotifyCollectionChangedAction action, TItem item, int index)
=> this.CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(action, item, index));
private void OnCollectionChangedReset()
=> this.CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
private void OnPropertyChanged() => this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.Count)));
}