解决DoubanFM第三方客户端UI线程与工作线程交互问题
最新文章:Virson's Blog
首先要感谢yk000123的慷慨开源,开源地址见:http://doubanfm.codeplex.com/
最近正好在学习WPF,然后在Codeplex上找到了用WPF写的DoubanFM的客户端,抱着练练手的心态,着手研究代码,研究了一段时间后,准备自己加一个新功能(新功能是关于下载的,但是由于豆瓣官方版权的原因,抱歉没法为博友们提供下载,敬请谅解),于是就有了如下的问题:
在使用ThreadPool.QueueUserWorkItem()方法开始后台下载歌曲的时候,无法禁用UI界面上的下载按钮。
遇到问题和广大码农想法一样,先搜索试试看(可怜的Google):
然后找到了两篇文章,引用一下:博客园-大传神 和 CSDN-yikai2009,在此感谢两位博主的倾情付出!
问题描述:由于其他线程拥有此对象,因此调用线程无法对其进行访问 (The calling thread cannot access this object because a different thread owns it)
分析:在 WPF 中,只有创建 DispatcherObject 的线程才能访问该对象。 例如,一个从主 UI 线程派生的后台线程不能更新在该 UI 线程上创建的 Button 的内容。 为了使该后台线程能够访问 Button 的 IsEnable属性,该后台线程必须将此工作委托给与该 UI 线程关联的 Dispatcher。 使用 Invoke 或 BeginInvoke 来完成此操作。 Invoke 是同步操作,而 BeginInvoke 是异步操作。 该操作将按指定的 DispatcherPriority 添加到 Dispatcher 的事件队列中。
Invoke 是同步操作;因此,直到回调返回之后才会将控制权返回给调用对象
最终实现代码:
/// <summary> /// 使用异步和断点续传的方式下载歌曲 /// </summary> private void StartDownloadSongs() { //DownloadSearch.Search(_player.CurrentSong.Title, _player.CurrentSong.Artist, _player.CurrentSong.Album); //BassEngine.Instance.OpenUrlAsync(_player.CurrentSong.FileUrl); string currentSongFileUrl = _player.CurrentSong.FileUrl; string downSavePath = DownSaveSetting.DownSavePath; int currentSongTypePoint = currentSongFileUrl.LastIndexOf('.'); string currentSongType = currentSongFileUrl.Substring(currentSongTypePoint, currentSongFileUrl.Length - currentSongTypePoint); string strFileName = string.Empty; //包含路径的歌曲名 string currentSongTitle = _player.CurrentSong.Title.Replace("/", "&"); //当前播放歌曲的歌曲名 string currentSongArtist = _player.CurrentSong.Artist.Replace("/" , "&"); //当前播放歌曲的作者 string currentSongAlbum = _player.CurrentSong.Album.Replace("/", "&"); //当前播放歌曲的专辑 if (DownSaveSetting.IsCreateFolderByArtist) { string savePathWithArtist = Path.Combine(downSavePath, currentSongArtist); if (!Directory.Exists(savePathWithArtist)) Directory.CreateDirectory(savePathWithArtist); strFileName = savePathWithArtist + "\\" + currentSongArtist + " - " + currentSongTitle + currentSongType; } else { if (!Directory.Exists(downSavePath)) Directory.CreateDirectory(downSavePath); strFileName = downSavePath + "\\" + currentSongArtist + " - " + currentSongTitle + currentSongType; } if (Download.IsExistFile(strFileName)) { MessageBoxResult result = MessageBox.Show(this, DoubanFM.Resources.Resources.DownFileIsExistHint, string.Empty, MessageBoxButton.OKCancel, MessageBoxImage.Information); if (result == MessageBoxResult.OK) { //开始文件下载线程 Download.DeleteFile(strFileName); StartDownloadSongsThread(strFileName, currentSongFileUrl); } } else { StartDownloadSongsThread(strFileName, currentSongFileUrl); } } private void StartDownloadSongsThread(string strFileName, string strUrl) { //开始文件下载线程 ThreadPool.QueueUserWorkItem(new WaitCallback(o => { this.BtnDownload.Dispatcher.BeginInvoke(new Action(delegate() { BtnDownload.IsEnabled = false; })); if (Download.DownloadFile(strFileName, strUrl)) this.BtnDownload.Dispatcher.BeginInvoke(new Action(delegate() { BtnDownload.IsEnabled = true; })); })); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架