/// <summary> /// 执行进度条动画 /// </summary> private void SetProgess(MainWindowStatusNotify notify) { //如果状态栏有正在执行的任务, 标识任务正在执行, 且隐藏清除消息按钮 if (notify.nowProgress < MainProgressBar.Maximum && !mIsProgressRunning) { mIsProgressRunning = true; ClearStatusBarTextButton.Visibility = Visibility.Collapsed; StopTaskButton.Visibility = Visibility.Visible; } //如果一个任务已经执行完毕, 则显示清除按钮 if (notify.nowProgress == MainProgressBar.Maximum && mIsProgressRunning) { mIsProgressRunning = false; ClearStatusBarTextButton.Visibility = Visibility.Visible; StopTaskButton.Visibility = Visibility.Collapsed; } //标识需要动画才会执行进度条动画 //if (notify.animateProgress) //{ //MainProgressBar.IsIndeterminate = true; Duration duration = new Duration(TimeSpan.FromMilliseconds(notify.progressDuration)); DoubleAnimation doubleanimation = new DoubleAnimation(notify.oldProgress, notify.nowProgress, duration); MainProgressBar.BeginAnimation(ProgressBar.ValueProperty, doubleanimation); //} //else //{ // //没有动画则直接赋值 // MainProgressBar.Dispatcher.Invoke(new Action<DependencyProperty, object>(MainProgressBar.SetValue), DispatcherPriority.Background, ProgressBar.ValueProperty, notify.nowProgress); //} }
/// <summary> /// 发送进度到主信息栏 /// </summary> /// <param name="notify"></param> /// <param name="message"></param> /// <param name="value"></param> /// <returns></returns> public static MainWindowStatusNotify CalcProgress(MainWindowStatusNotify notify, string message, double value) { notify.message = message; notify.oldProgress = notify.nowProgress; notify.nowProgress = value; return(notify); }
/// <summary> /// 设置主窗口状态栏文及进度 /// </summary> /// <param name="notify"></param> public void SetStatustProgess(MainWindowStatusNotify notify) { MainProgressBar.Dispatcher.Invoke(() => { SetStatusBarText(notify.alertLevel, notify.message); SetProgess(notify); }); //this.Dispatcher.BeginInvoke((Action)delegate () //{ // SetStatusBarText(notify.alertLevel, notify.message); // SetProgess(notify); //}); }
/// <summary> /// 读取文件工作任务 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void DoReadDeviceFileTask(object sender, DoWorkEventArgs workArgs) { var args = (DeviceSyncReadArgs)workArgs.Argument; var resultNotify = new MainWindowStatusNotify() { message = "文件读取完成" }; workArgs.Result = resultNotify; //多设备且未手动选择设备 if (null == args.Device) { resultNotify.message = "没有待同步的目标设备"; resultNotify.alertLevel = AlertLevel.ERROR; return; } //多盘符且未手动选择盘符 if (null == args.MediaDrive) { resultNotify.message = "没有待同步的目标盘符"; resultNotify.alertLevel = AlertLevel.ERROR; return; } //进度通知 var progressEvent = new DeviceSyncReadProgressItem { ProgressType = ReadSyncFileTaskProgressType.TEXT_ONLY, Notify = new MainWindowStatusNotify { message = "正在读取路径配置...", alertLevel = AlertLevel.RUN, nowProgress = 99 } }; mReadDeviceFileWorker.ReportProgress(0, progressEvent); //从数据库读取 var dataSet = SQLite.SqlTable("SELECT pc_path, mobile_path FROM media_sync_config where enable = 1", null); if (null == dataSet || dataSet.Rows.Count == 0) { resultNotify.message = "无法读取路径配置"; resultNotify.alertLevel = AlertLevel.WARN; return; } //封装进对象 var syncPathList = new List <MediaSyncConfig>(); foreach (DataRow dataRow in dataSet.Rows) { syncPathList.Add(new SyncConfigViewModel() { PcPath = Convert.ToString(dataRow["pc_path"]), MobilePath = Convert.ToString(dataRow["mobile_path"]), }); } progressEvent.Notify.message = "正在连接到设备..."; mReadDeviceFileWorker.ReportProgress(0, progressEvent); //筛选WPD设备 using (args.Device) { args.Device.Connect(); foreach (var e in syncPathList) { bool isPcPathExists = Directory.Exists(e.PcPath), isMobilePathExists = args.Device.DirectoryExists(Path.Combine(args.MediaDrive.NameView, e.MobilePath)); if (!isPcPathExists && !isMobilePathExists) { //如果两端都不存在目标文件夹, 则跳过 continue; } progressEvent.Notify.message = string.Format("正在读取文件列表[{0}]...", e.PcPath); mReadDeviceFileWorker.ReportProgress(0, progressEvent); //读取PC目录下的文件列表 var pcFiles = isPcPathExists ? FileUtil.GetFileNameFromFullPath(Directory.GetFiles(e.PcPath)) : new string[0]; //读取移动设备下的文件列表 //var xxx = args.Device.GetFileSystemEntries(Path.Combine(args.MediaDrive.NameView, e.MobilePath)); //isMobilePathExists ? FileUtil.GetFileNameFromFullPath(args.Device.GetFiles(Path.Combine(args.MediaDrive.NameView, e.MobilePath))) : var mobileFileList = new List <string>(); if (isMobilePathExists) { var fullMobileFolderPath = Path.Combine(args.MediaDrive.NameView, e.MobilePath); var fullNames = args.Device.EnumerateFiles(fullMobileFolderPath); foreach (var fullName in fullNames) { //使用Win函数读取文件名 var winSupportName = Path.GetFileName(fullName); //通过路径裁剪方式获得文件名 var substringName = fullName.Replace(fullMobileFolderPath + Path.DirectorySeparatorChar, string.Empty); //如果两种方式取得的文件名不一致, 说明这个文件名在windows上是不合法的 if (!winSupportName.Equals(substringName)) { //如果路径包含windows路径符, 记录错误并跳过 if (substringName.Contains(Path.DirectorySeparatorChar)) { //发送win10通知, 提醒人工处理此文件 //通知官方文档 https://docs.microsoft.com/en-us/windows/uwp/design/shell/tiles-and-notifications/send-local-toast-desktop new ToastContentBuilder() .AddText("文件收集失败") .AddText("不支持的文件名") .AddText(fullName) .Show(); continue; } //取得后缀名 var extendName = Path.GetExtension(substringName); //重命名移动设备上的文件名, 使用随机文件名 var newName = string.Format("{0}{1}{2}{3}", DateTime.Now.ToString("yyyyMMddHHmmss"), "_auto_rename_", RandomUtil.MakeSring(false, 6), extendName); args.Device.Rename(fullName, newName); mobileFileList.Add(newName); //发送win10通知, 提醒文件已改名 new ToastContentBuilder() .AddText("文件重命名提醒") .AddText(fullMobileFolderPath) .AddText(substringName + " -> " + newName) .Show(); continue; } mobileFileList.Add(winSupportName); } } var mobileFilesArr = mobileFileList.ToArray(); //找出差异文件 var filesOnlyInMobile = DataUtil.FindDiffEls(pcFiles, mobileFilesArr); var filesOnlyInPc = DataUtil.FindDiffEls(mobileFilesArr, pcFiles); //不存在差异则直接跳过当前文件夹 if (DataUtil.IsEmptyCollection(filesOnlyInMobile) && DataUtil.IsEmptyCollection(filesOnlyInPc)) { continue; } if (!DataUtil.IsEmptyCollection(filesOnlyInPc)) { if (!CollectAndNotify(filesOnlyInPc, workArgs, e, SyncDeviceType.PC)) { //不成功通常是任务中断 args.Device.Disconnect(); resultNotify.message = "已停止"; return; } } if (!DataUtil.IsEmptyCollection(filesOnlyInMobile)) { if (!CollectAndNotify(filesOnlyInMobile, workArgs, e, SyncDeviceType.PHONE)) { args.Device.Disconnect(); resultNotify.message = "已停止"; return; } } } args.Device.Disconnect(); } }
/// <summary> /// 执行同步文件的后台任务 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void DoSyncFileTask(object sender, DoWorkEventArgs e) { var winProgress = new MainWindowStatusNotify() { alertLevel = AlertLevel.RUN, animateProgress = true, progressDuration = 100, nowProgress = 0 }; var isTaskStop = false; //当前执行的队列编号 var curTaskNo = 1; //当前队列最大元素数量 var maxedQueueCount = mSyncTaskQueue.Count; while (mSyncTaskQueue.Count > 0) { var arg = new DeviceSyncTaskArgs(); var isPick = mSyncTaskQueue.TryDequeue(out arg); if (!isPick) { continue; } //每个队列的分片进度 double eachBaseProgress = 0; //筛选WPD设备 using (var device = arg.Device) { device.Connect(); //检查目标文件夹是否存在, 不存在则创建 if (!Directory.Exists(arg.Item.PcFolderNameView)) { FileUtil.CreateFolder(arg.Item.PcFolderNameView); } var targetMobileFolder = Path.Combine(arg.DevicePath, arg.Item.MobileFolderNameView); if (!device.DirectoryExists(targetMobileFolder)) { device.CreateDirectory(targetMobileFolder); } //将两端的文件合并到一个集合 var allItems = arg.Item.PcItemList.ToList(); allItems.AddRange(arg.Item.MobileItemList.ToList()); var fileCounter = 1; allItems.ForEach((syncFile) => { //检查任务是否取消 if (mSyncFileBgWorker.CancellationPending) { isTaskStop = true; return; } //如果队列数量增大超过初始量, 记录一个最大数量 if (mSyncTaskQueue.Count + 1 > maxedQueueCount) { maxedQueueCount = mSyncTaskQueue.Count + 1; } //当前队列数量=此队列拥有过的最大数量 var curQueueCount = maxedQueueCount; //计算每个队列的分片进度 eachBaseProgress = 100 / curQueueCount; //每个队列的基础进度, 从0开始, 以分片进度递增 double baseProgress = 100 - (mSyncTaskQueue.Count + 1) * eachBaseProgress; //计算每个文件的分片进度 double eachFileProgress = eachBaseProgress / allItems.Count; //文件的执行进度, 从0开始递增 double fileProgress = eachFileProgress * fileCounter - eachFileProgress; //总进度 = 基础进度 + 文件进度 WindowUtil.CalcProgress(winProgress, string.Format("主任务 [{0}/{1}], 子任务 [{2}/{3}], 正在复制 [ {4} ]", curTaskNo, curQueueCount, fileCounter, allItems.Count, syncFile.NameView), baseProgress + fileProgress); arg.Progress = winProgress; arg.ProgressType = SyncTaskProgressType.SUB_ITEM_FINISH; mSyncFileBgWorker.ReportProgress(0, arg); //执行同步 if (syncFile.SourceView == SyncDeviceType.PC) { //电脑端, 需要复制到移动端 var targetFolder = Path.Combine(arg.DevicePath, arg.Item.MobileFolderNameView); using (FileStream stream = System.IO.File.OpenRead(Path.Combine(arg.Item.PcFolderNameView, syncFile.NameView))) { device.UploadFile(stream, Path.Combine(targetFolder, syncFile.NameView)); } } else { MediaFileInfo fileInfo = device.GetFileInfo(Path.Combine(arg.DevicePath, arg.Item.MobileFolderNameView, syncFile.NameView)); fileInfo.CopyTo(Path.Combine(arg.Item.PcFolderNameView, syncFile.NameView)); } fileProgress = eachFileProgress * fileCounter; WindowUtil.CalcProgress(winProgress, string.Format("主任务 [{0}/{1}], 子任务 [{2}/{3}], 正在复制 [ {4} ]", curTaskNo, curQueueCount, fileCounter, allItems.Count, syncFile.NameView), baseProgress + fileProgress); arg.Source = syncFile.SourceView; arg.DeviceSyncItem = syncFile; mSyncFileBgWorker.ReportProgress(0, arg); fileCounter++; }); device.Disconnect(); } arg.IsOk = !isTaskStop; arg.ProgressType = SyncTaskProgressType.QUEUE_FINISH; if (!isTaskStop) { //一个队列执行完之后, 发送当前队列进度 WindowUtil.CalcProgress(arg.Progress, string.Format("主任务 [{0}/{1}]同步完成", curTaskNo, maxedQueueCount), curTaskNo * eachBaseProgress); mSyncFileBgWorker.ReportProgress(0, arg); curTaskNo++; } else { mSyncFileBgWorker.ReportProgress(0, arg); } } e.Result = !isTaskStop; }