【发布时间】:2011-09-16 14:58:17
【问题描述】:
拥有一个大多数属性都非常轻量级的对象 - 最多 200 个字符的文本。一个属性是 FlowDocument,它可能很大并且想要异步检索它。当我设置 Async = True 并显示以下消息时失败:“调用线程无法访问此对象,因为不同的线程拥有它。”
<FlowDocumentReader Name="FlowDocumentPageViewer1" HorizontalAlignment="Stretch"
Document="{Binding Source={x:Static Application.Current}, Path=MyGabeLib.Search.SelectedDoc.DocFlowDocument, Mode=OneWay, IsAsync=True}" />
Production Get 更复杂,但在 IsAsyc True 上同样失败,即使使用简单的硬编码 FlowDocument。
public FlowDocument DocFlowDocument
{
get
{
FlowDocument docFlowDocumentFast = new FlowDocument();
Paragraph p = new Paragraph();
Run r = new Run();
r.Foreground = System.Windows.Media.Brushes.Red;
r.Text = "Hard Code Simple FlowDocument";
p.Inlines.Add(r);
docFlowDocumentFast.Blocks.Add(p);
return docFlowDocumentFast;
}
{
它确实调用了 SelectedDoc.DocFlowDocument 并返回了文档! 使用 IsAsync = False 它运行得很好。 我认为问题在于静态源,但显然我不知道如何解决它。
public partial class App : Application
{
private static GabeLib staticGabeLib = new GabeLib();
private GabeLib myGabeLib = staticGabeLib;
public GabeLib MyGabeLib
{ get { return myGabeLib; } }
public static GabeLib StaticGabeLib
{ get { return staticGabeLib; } }
}
当 GabeLib 启动时,它会从数据库中读取应用程序和用户设置。
如果有更好的方法来解决这个问题,我会尝试一下。由于 FlowDocument 可以为 3 mb,而所有其他属性的组合为 10K,这对性能造成了很大的影响,最常用的按钮是下一个对象。 FlowDocument 来自 SQL 中的 varchar(max),并使用换行符和突出显示的单词进行格式化。它不仅很大 - 与其他房产相比,它也很昂贵。
FlowDocumentReader 本身似乎有一些异步支持,因为在大型文档上我可以快速获得第一页,然后页面以大约 100/秒的速度加载。但我仍然希望它在检索到所有其他属性后获得第 1 页。
问题正如马丁所说“由于 FlowDocument 是一个调度程序对象,它只能从创建它的线程访问”。
解决方案是序列化为 XAML 字符串。
public string XAMLdocFlowDocument
{
get
{
Thread.Sleep(6000);
return XamlWriter.Save(FlowDocumentSlow);
}
}
使用转换器绑定到字符串
<FlowDocumentReader Grid.Row="3" Grid.Column="0" VerticalAlignment="Stretch"
Document="{Binding Path=XAMLdocFlowDocument, IsAsync=True,
Converter={StaticResource flowDocumentToXamlConverter}, Mode=OneWay}" />
转换器
[ValueConversion(typeof(string), typeof(FlowDocument))]
public class FlowDocumentToXamlConverter : IValueConverter
{
#region IValueConverter Members
/// <summary>
/// Converts from XAML markup to a WPF FlowDocument.
/// </summary>
public object Convert(object value, System.Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
var flowDocument = new FlowDocument();
if (value != null)
{
var xamlText = (string)value;
flowDocument = (FlowDocument)XamlReader.Parse(xamlText);
}
// Set return value
return flowDocument;
}
【问题讨论】:
-
这种情况下的 FallbackValue 是什么?是否需要在绑定中指定(因为这可能会在异步操作处理时应用?)
-
仍然失败并返回 FallbackValue。如果我执行 PriorityBinding,它将通过非异步,甚至调用异步 get,但随后在 XMAL 中失败。
-
为什么投反对票?什么不清楚、缺乏研究或没有用处?
-
再次感谢 Marten。我最近升级了代码以使用 BackgroundWorker 而不是 IsAsync=True 并获得了 10 倍的性能提升。如果您有一个返回少量文本的昂贵进程,否则 IsAsync=True 非常好,否则直接使用 BackgroundWorker 或线程。 Dispatcher 很复杂,但它的存在是有充分理由的。
标签: wpf binding asynchronous flowdocument flowdocumentreader