我试图弄清楚如何将dispatcherObject(在我的情况下bitmapsource)复制到另一个线程中。

用例:
我有一个WPF应用需要在新线程中显示窗口(该应用实际上是Outlook Addin,我们需要这样做,因为Outlook在主UI线程中有一些挂钩,并且正在窃取我们需要使用的某些热键 - '在transpation'在Outlook Interop中,WPF(我们用于UI)和Winforms(我们需要使用某些Microsoft提供的Winforms控件)。

因此,我实现了WPFMessageBox的实现,它是通过设置一些静态属性来配置的 - 并且其中一个是ICON的bitmapsource。它可以使用以便在启动中我可以设置wpfmessagebox.icon一次,从那以后,每个wpfmessagebox都将具有相同的图标。

问题在于,分配给图标的BitMapsource是一个dispatcherObject,当读取时,它将抛出InvalidoperationException:“该调用线程无法访问此对象,因为不同的线程拥有它。”。

我如何克隆该位图像库中的实际线程?它具有clone()和clonecurrentValue()方法,它们不起作用(它们也引发了相同的例外)。我也想使用primateicon.dispatcher.invoke(在此处进行克隆) - 但是Bitmapsource的调度程序是无效的,仍然 - 我仍然会在错误的线程上创建一个副本,并且仍然无法在我的线上使用它。 bitmapsource.isfrozen == true。

关于如何将bitmapsource复制到不同线程中的任何想法(不完全从新线程中的图像文件重构)吗?

编辑:因此,冻结无济获取InvalidOperationException:“呼叫线程无法访问此对象,因为一个不同的线程拥有它。”具有以下堆栈跟踪:

    WindowsBase.dll!System.Windows.Threading.Dispatcher.VerifyAccess() + 0x4a bytes 
    WindowsBase.dll!System.Windows.Threading.DispatcherObject.VerifyAccess() + 0xc bytes    
    PresentationCore.dll!System.Windows.Media.Imaging.BitmapDecoder.Frames.get() + 0xe bytes    
    PresentationFramework.dll!MS.Internal.AppModel.IconHelper.GetIconHandlesFromBitmapFrame(object callingObj = {WPFControls.WPFMBox.WpfMessageBoxWindow: header}, System.Windows.Media.Imaging.BitmapFrame bf = {System.Windows.Media.Imaging.BitmapFrameDecode}, ref MS.Win32.NativeMethods.IconHandle largeIconHandle = {MS.Win32.NativeMethods.IconHandle}, ref MS.Win32.NativeMethods.IconHandle smallIconHandle = {MS.Win32.NativeMethods.IconHandle}) + 0x3b bytes   
>   PresentationFramework.dll!System.Windows.Window.UpdateIcon() + 0x118 bytes  
    PresentationFramework.dll!System.Windows.Window.SetupInitialState(double requestedTop = NaN, double requestedLeft = NaN, double requestedWidth = 560.0, double requestedHeight = NaN) + 0x8a bytes  
    PresentationFramework.dll!System.Windows.Window.CreateSourceWindowImpl() + 0x19b bytes  
    PresentationFramework.dll!System.Windows.Window.SafeCreateWindow() + 0x29 bytes 
    PresentationFramework.dll!System.Windows.Window.ShowHelper(object booleanBox) + 0x81 bytes  
    PresentationFramework.dll!System.Windows.Window.Show() + 0x48 bytes 
    PresentationFramework.dll!System.Windows.Window.ShowDialog() + 0x29f bytes  
    WPFControls.dll!WPFControls.WPFMBox.WpfMessageBox.ShowDialog(System.Windows.Window owner = {WPFControlsTest.MainWindow}) Line 185 + 0x10 bytes  C#
有帮助吗?

解决方案

关键是 创造 您要使用的线程上的位图。因此,每次打开新线程上的新窗口时,您都不能在某些静态字段/属性中缓存图标(从文件,资源,流或其他)加载。

BitmapFrame只能在其创建的线程上使用。

正如您正确说明的那样,即使是克隆也无法使用(这很烂)。

我有 确切地 同样的问题并仅通过每次加载图标来解决,在我的特殊情况下,只需致电

// get your stream somewhere - 
window.Icon = BitmapFrame.Create(stream)

这就是您可以从WPF中的资源获取图标的方式:

var streamResourceInfo = Application.GetResourceStream(new Uri(@"pack://application:,,,/YourAssembly;relative path to the icon", UriKind.RelativeOrAbsolute));
// use streamResourceInfo.Stream 

其他提示

一旦您打电话 Freeze, ,它应该在多个线程上工作。

bitmapSourceForOtherThread = new WriteableBitmap(previousBitmapSource);

这是有代价的,但是与序列化相比,这很便宜。

长答案.

一个确实有效的解决方法,尽管不是很有性能,但正在从图像数据中创建一个内存流,然后重建要使用的线程上的图像。

示例 BitmapSource:

Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)delegate()
{
    //serialize image on UI thread
    imageStream = GetImageBytes(cameraImage);
}

...
//reconstruct image on a different thread:
Bitmap bitmap = new Bitmap(imageStream); 

private MemoryStream GetImageBytes(BitmapSource image)
{
    MemoryStream ms = new MemoryStream();
    BitmapEncoder encoder = new PngBitmapEncoder();
    encoder.Frames.Add(BitmapFrame.Create(image));
    encoder.Save(ms);
    ms.Seek(0, SeekOrigin.Begin);
    return ms;
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top