解决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; }));
            }));
        }

 

posted @ 2013-07-09 23:13  学海无涯1999  阅读(506)  评论(0编辑  收藏  举报