public Item(string filename, long?size, string url, IRelay relay, ObservableCollection <Item> collection) { URL = url; Filename = Path.GetFileName(filename); TotalSize = size; if (File.Exists(filename)) { using (var icon = Icon.ExtractAssociatedIcon(filename)) using (var bmp = icon.ToBitmap()) FileIcon = Imaging.CreateBitmapSourceFromHBitmap(bmp.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); } if (relay != null) { long lastDownloaded = 0; double lastLastBps = 0, lastBps = 0, inverseTotal = (TotalSize ?? 0) > 0 ? (100.0 / TotalSize.Value) : 1; relay.OnProgress += (downloaded, total) => { double bps = downloaded - lastDownloaded; bps = (bps + (lastBps > 0 ? lastBps : bps) + (lastLastBps > 0 ? lastLastBps : bps)) / 3.0; lastLastBps = lastBps; lastBps = bps; lastDownloaded = downloaded; Bps = $"{((long)bps).FormatBytes()}/sec"; Downloaded = downloaded; Progress = downloaded * inverseTotal; if (TotalSize.HasValue) { Remaining = bps > 0 ? TimeSpan.FromSeconds((TotalSize.Value - downloaded) / bps) : (TimeSpan?)null; Status = $"{Downloaded.FormatBytes()} of {TotalSize.Value.FormatBytes()} downloaded"; } else { Status = $"{Downloaded.FormatBytes()} downloaded"; } }; relay.OnStart += () => { Status = "download started.."; IsIndeterminate = !TotalSize.HasValue; }; relay.OnDisconnect += () => { Status = "disconnected, waiting to resume.."; Bps = null; Remaining = null; IsIndeterminate = false; }; } Cancel = new Command(() => { collection.Remove(this); relay?.Cancel(); }); Copy = new Command(() => Clipboard.SetDataObject(URL, true)); }