我正在创建一个在不同线程中标记为STA的窗口,该窗口具有一些控件和图像。
然后我关闭此窗口并在主UI线程中打开另一个窗口,在其中我有一个打印对话框,并使用以下代码获取FixedDocumentSequence:
自从StackTrace对
但我仍然遇到错误。 我希望找到一种适用于我WPF应用程序中所有图像的解决方案。
希望我表达清楚了,因为用两个线程和某些异常来解释这个问题相当奇怪。
编辑:经过进一步测试,现在我能够向您展示一个具有手头问题的可重现应用程序,希望这样更清晰。
您需要3个窗口,1个文件夹和1个图像。 在我的情况下,它是MainWindow.xaml,Window1.xaml和Window2.xaml。
Images是文件夹的名称,在其中有一个名为“plus.png”的图像。
MainWindow.xaml:
然后我关闭此窗口并在主UI线程中打开另一个窗口,在其中我有一个打印对话框,并使用以下代码获取FixedDocumentSequence:
var tempFileName = System.IO.Path.GetTempFileName();
File.Delete(tempFileName);
using (var xpsDocument = new XpsDocument(tempFileName, FileAccess.ReadWrite, CompressionOption.NotCompressed))
{
var writer = XpsDocument.CreateXpsDocumentWriter(xpsDocument);
writer.Write(this.DocumentPaginator);
}
using (var xpsDocument = new XpsDocument(tempFileName, FileAccess.Read, CompressionOption.NotCompressed))
{
var xpsDoc = xpsDocument.GetFixedDocumentSequence();
return xpsDoc;
}
在线上:
writer.Write(this.DocumentPaginator);
我从一个内部调用 VerifyAccess中收到了 InvalidOperationException,以下是StackTrace:
bei System.Windows.Threading.Dispatcher.VerifyAccess()
bei System.Windows.Threading.DispatcherObject.VerifyAccess()
bei System.Windows.Media.Imaging.BitmapDecoder.get_IsDownloading()
bei System.Windows.Media.Imaging.BitmapFrameDecode.get_IsDownloading()
bei System.Windows.Media.Imaging.BitmapSource.FreezeCore(Boolean isChecking)
bei System.Windows.Freezable.Freeze(Boolean isChecking)
bei System.Windows.PropertyMetadata.DefaultFreezeValueCallback(DependencyObject d, DependencyProperty dp, EntryIndex entryIndex, PropertyMetadata metadata, Boolean isChecking)
bei System.Windows.Freezable.FreezeCore(Boolean isChecking)
bei System.Windows.Media.Animation.Animatable.FreezeCore(Boolean isChecking)
bei System.Windows.Freezable.Freeze()
bei System.Windows.Media.DrawingDrawingContext.DrawImage(ImageSource imageSource, Rect rectangle, AnimationClock rectangleAnimations)
bei System.Windows.Media.DrawingDrawingContext.DrawImage(ImageSource imageSource, Rect rectangle)
bei System.Windows.Media.DrawingContextDrawingContextWalker.DrawImage(ImageSource imageSource, Rect rectangle)
bei System.Windows.Media.RenderData.BaseValueDrawingContextWalk(DrawingContextWalker ctx)
bei System.Windows.Media.DrawingServices.DrawingGroupFromRenderData(RenderData renderData)
bei System.Windows.UIElement.GetDrawing()
bei System.Windows.Media.VisualTreeHelper.GetDrawing(Visual reference)
bei System.Windows.Xps.Serialization.VisualTreeFlattener.StartVisual(Visual visual)
bei System.Windows.Xps.Serialization.ReachVisualSerializer.SerializeTree(Visual visual, XmlWriter resWriter, XmlWriter bodyWriter)
bei System.Windows.Xps.Serialization.ReachVisualSerializer.SerializeObject(Object serializedObject)
bei System.Windows.Xps.Serialization.DocumentPageSerializer.SerializeChild(Visual child, SerializableObjectContext parentContext)
bei System.Windows.Xps.Serialization.DocumentPageSerializer.PersistObjectData(SerializableObjectContext serializableObjectContext)
bei System.Windows.Xps.Serialization.ReachSerializer.SerializeObject(Object serializedObject)
bei System.Windows.Xps.Serialization.DocumentPageSerializer.SerializeObject(Object serializedObject)
bei System.Windows.Xps.Serialization.DocumentPaginatorSerializer.PersistObjectData(SerializableObjectContext serializableObjectContext)
bei System.Windows.Xps.Serialization.DocumentPaginatorSerializer.SerializeObject(Object serializedObject)
bei System.Windows.Xps.Serialization.XpsSerializationManager.SaveAsXaml(Object serializedObject)
bei System.Windows.Xps.XpsDocumentWriter.SaveAsXaml(Object serializedObject, Boolean isSync)
bei System.Windows.Xps.XpsDocumentWriter.Write(DocumentPaginator documentPaginator)
自从StackTrace对
BitmapSource/BitmapDecoder
进行了一些调用,我考虑尝试删除图像并将原地图像控件的源设置为null。<Image Source={x:Null} />
我将所有图片都做了这个处理后,我的代码运行顺畅了,不再出现异常。
我尝试使用以下自定义图像来解决这个问题:
public class CustomImage : Image
{
public CustomImage()
{
this.Loaded += CustomImage_Loaded;
this.SourceUpdated += CustomImage_SourceUpdated;
}
private void CustomImage_SourceUpdated(object sender, System.Windows.Data.DataTransferEventArgs e)
{
FreezeSource();
}
private void CustomImage_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
FreezeSource();
}
private void FreezeSource()
{
if (this.Source == null)
return;
var freeze = this.Source as Freezable;
if (freeze != null && freeze.CanFreeze && !freeze.IsFrozen)
freeze.Freeze();
}
}
但我仍然遇到错误。 我希望找到一种适用于我WPF应用程序中所有图像的解决方案。
希望我表达清楚了,因为用两个线程和某些异常来解释这个问题相当奇怪。
编辑:经过进一步测试,现在我能够向您展示一个具有手头问题的可重现应用程序,希望这样更清晰。
您需要3个窗口,1个文件夹和1个图像。 在我的情况下,它是MainWindow.xaml,Window1.xaml和Window2.xaml。
Images是文件夹的名称,在其中有一个名为“plus.png”的图像。
MainWindow.xaml:
<StackPanel Orientation="Vertical">
<StackPanel.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Margin"
Value="0,0,0,5"></Setter>
</Style>
</StackPanel.Resources>
<Button Content="Open Window 1" Click="OpenWindowInNewThread" />
<Button Content="Open Window 2" Click="OpenWindowInSameThread" />
</StackPanel>
MainWindow.xaml.cs:
private void OpenWindowInNewThread(object sender, RoutedEventArgs e)
{
var th = new Thread(() =>
{
SynchronizationContext.SetSynchronizationContext(new DispatcherSynchronizationContext(Dispatcher.CurrentDispatcher));
var x = new Window1();
x.Closed += (s, ec) => Dispatcher.CurrentDispatcher.BeginInvokeShutdown(DispatcherPriority.Background);
x.Show();
System.Windows.Threading.Dispatcher.Run();
});
th.SetApartmentState(ApartmentState.STA);
th.IsBackground = true;
th.Start();
}
private void OpenWindowInSameThread(object sender, RoutedEventArgs e)
{
var x = new Window2();
x.Show();
}
Window1.xaml:
<StackPanel Orientation="Horizontal">
<ToggleButton Template="{StaticResource PlusToggleButton}" />
</StackPanel>
Window1.xaml.cs: 这里没有代码,只有构造函数...
Window2.xaml:
<StackPanel Orientation="Horizontal">
<ToggleButton Template="{StaticResource PlusToggleButton}" />
<Button Content="Print Me" Click="Print"></Button>
</StackPanel>
Window2.xaml.cs:
public void Print(object sender, RoutedEventArgs e)
{
PrintDialog pd = new PrintDialog();
pd.PrintVisual(this, "HelloWorld");
}
App.xaml:
<ControlTemplate x:Key="PlusToggleButton"
TargetType="{x:Type ToggleButton}">
<Image Name="Image"
Source="/WpfApplication1;component/Images/plus.png"
Stretch="None" />
</ControlTemplate>
重现步骤:
- 在MainWindow中点击“打开窗口1”的按钮。
- 一个窗口将在第二个UI线程中弹出,请关闭此窗口。
- 点击“打开窗口2”按钮
- 一个窗口将在主UI线程中弹出
- 点击“打印我”按钮,应用程序会崩溃
希望现在更容易帮助我了解问题。
编辑2:
添加了丢失的代码部分,对此错误感到抱歉。
另外一个可能有助于解决问题的信息是,当您按相反的顺序点击按钮 - 先是窗口2,然后是窗口1 - 然后尝试打印时,不会触发任何异常,因此我仍然认为这是一些图像缓存问题,当图像首次加载到主UI线程时,如果不行,就会失败。