由于此处描述的问题:
WPD MTP stream hangs on commit
尽管使用BackgroundWorker进行呼叫,但我的WPF程序的UI处于挂起状态(意味着它在执行某项任务时无响应)。我已经读过一些关于这个事实的事实,即执行操作的COM对象是在UI线程上创建的,但是当我打破挂起的代码时,我发现它实际上是在执行的一个WorkerThread而不是MainThread,这似乎表明这不是问题(虽然我是一个线程新手)。任何人都可以解释为什么会发生这种情况以及我应该如何解决这个UI问题?
从基类开始设置backgroundworker:
public void Sync()
{
SyncBackgroundWorker.WorkerReportsProgress = true;
SyncBackgroundWorker.WorkerSupportsCancellation = true;
SyncBackgroundWorker.DoWork += SyncBackgroundWorker_DoWork;
SyncBackgroundWorker.ProgressChanged += SyncBackgroundWorker_ProgressChanged;
SyncBackgroundWorker.RunWorkerCompleted += SyncBackgroundWorker_RunWorkerCompleted;
SyncBackgroundWorker.RunWorkerAsync();
}
protected void SyncBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
// Retrieve needed files from iTunes and compose m3u playlists
var syncInfo = this.getSyncInfo();
// Save m3u files to music root on target
this.saveM3UPlaylists(syncInfo.M3Us);
}
从扩展基类的类(最后一行启动文件副本):
protected override void saveM3UPlaylists(List<FileInfo> M3UPlaylists)
{
foreach (var file in this.Folder.GetFiles())
{
if (file.Extension == ".m3u")
file.Delete();
}
int numPlaylists = this.Playlists.Count;
for (int i = 0; i < numPlaylists; i++)
PortableDevices.PortableDeviceFile.CopyFileToDevice(this.Folder, makeValidFileName(this.Playlists[i].Name + ".m3u"), M3UPlaylists[i]);
}
来自相关便携设备类。 targetStream.Commit(0)
部分导致实际冻结,如前面给出的链接中所述。请注意,在程序开始时,在设置与设备的连接时,先前已初始化COM对象(IPortableDevice)parent.Device.Content
。
public static void CopyFileToDevice(PortableDeviceFolder parent, string name, FileInfo file)
{
IPortableDeviceValues values = GetRequiredPropertiesForContentType(parent.Id, name, file.Length);
PortableDeviceApiLib.IStream tempStream;
uint blockSize = 0;
parent.Device.Content.CreateObjectWithPropertiesAndData(
values,
out tempStream,
ref blockSize,
null);
System.Runtime.InteropServices.ComTypes.IStream targetStream =
(System.Runtime.InteropServices.ComTypes.IStream)tempStream;
try
{
using (var sourceStream = file.OpenRead())
{
var buffer = new byte[blockSize];
int bytesRead;
do
{
bytesRead = sourceStream.Read(buffer, 0, (int)blockSize);
targetStream.Write(buffer, bytesRead, IntPtr.Zero);
} while (bytesRead > 0);
}
targetStream.Commit(0);
}
finally
{
Marshal.ReleaseComObject(tempStream);
}
parent.Refresh();
}