如何强制FlowDocument在DataContext集上刷新其内容
本文关键字:刷新 何强制 FlowDocument DataContext | 更新日期: 2024-09-25 02:31:38
我正在尝试使用带有绑定的FlowDocument来拥有单独的模板,该模板能够用数据模型中的实际数据填充。然后我将其转换为图像并打印或保存在硬盘上。为了将FlowDocument的Run与数据模型绑定,我使用了本文中的代码:https://msdn.microsoft.com/en-us/magazine/dd569761.aspx
FlowDocument模板如下:
<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:p="clr-namespace:Labels;assembly=DataModel.Impl"
PageWidth="200" MinPageWidth="200" PageHeight="200" MinPageHeight="200">
<Section>
<Paragraph>
<p:BindableRun BoundText="{Binding Path=Text}"/>
</Paragraph>
</Section>
</FlowDocument>
BindableRun的代码:
public class BindableRun : Run
{
public static readonly DependencyProperty BoundTextProperty = DependencyProperty.Register("BoundText", typeof(string), typeof(BindableRun),
new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure, OnBoundTextChanged, CoerceText));
public BindableRun()
{
FlowDocumentHelpers.FixupDataContext(this);
}
private static void OnBoundTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((Run)d).Text = (string)e.NewValue;
}
private static object CoerceText(DependencyObject d, object value)
{
return value;
}
public String BoundText
{
get { return (string)GetValue(BoundTextProperty); }
set { SetValue(BoundTextProperty, value); }
}
}
然后我加载模板并在其中设置DataContext:
private class DataClass
{
public string Text { get; set; }
}
private static FlowDocument LoadFlowDocument(string path)
{
using (var xamlFile = new FileStream(path, FileMode.Open, FileAccess.Read))
{
return XamlReader.Load(xamlFile) as FlowDocument;
}
}
private static void FlowDoc2Image(FlowDocument document, DataClass dataContext, Stream imageStream)
{
var flowDocumentScrollViewer = new FlowDocumentScrollViewer
{
VerticalScrollBarVisibility = ScrollBarVisibility.Hidden,
HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden,
DataContext = dataContext
};
flowDocumentScrollViewer.Document = document;
flowDocumentScrollViewer.Measure(new Size(999999999, 999999999));
//1st pass
flowDocumentScrollViewer.Arrange(new Rect(0, 0, flowDocumentScrollViewer.ActualWidth, flowDocumentScrollViewer.ActualHeight));
//2nd pass. It's not code duplication! Do not remove!
flowDocumentScrollViewer.Arrange(new Rect(0, 0, flowDocumentScrollViewer.ActualWidth, flowDocumentScrollViewer.ActualHeight));
var bitmapRenderer =
new RenderTargetBitmap((int)flowDocumentScrollViewer.ActualWidth, (int)flowDocumentScrollViewer.ActualHeight, 96, 96, PixelFormats.Pbgra32);
bitmapRenderer.Render(flowDocumentScrollViewer);
var pngEncoder = new PngBitmapEncoder { Interlace = PngInterlaceOption.On };
pngEncoder.Frames.Add(BitmapFrame.Create(bitmapRenderer));
pngEncoder.Save(imageStream);
}
public void Test()
{
var doc = LoadFlowDocument("C:''Experiments''DocWithBinding.xaml");
var context = new DataClass {Text = "SomeText"};
doc.DataContext = context;
using (var imageStream = new FileStream("C:''Experiments''image.png", FileMode.OpenOrCreate, FileAccess.Write))
{
FlowDoc2Image(doc, context, imageStream);
}
}
但什么也没发生。我试图在BindableRun中设置断点来更改它的值。我从来没有到过那里。更改DataContext不会影响文档。
不再需要BindableRun类。来自Run.Text
:的备注部分
从.NET Framework 4开始,Run对象的Text属性是依赖项属性,这意味着您可以绑定Text属性转换为数据源。
因此,您的FlowDocument文件可能如下所示:
<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
PageWidth="200" MinPageWidth="200" PageHeight="200" MinPageHeight="200">
<Section>
<Paragraph>
<Run Text="{Binding Text}"/>
</Paragraph>
</Section>
</FlowDocument>
我已经加载了这个,如您的问题中所示,为其DataContext分配了一个DataClass实例,并成功地将其显示在RichTextBox:中
<Grid>
<RichTextBox x:Name="rtb"/>
</Grid>
代码背后:
private class DataClass
{
public string Text { get; set; }
}
public MainWindow()
{
InitializeComponent();
var doc = LoadFlowDocument("DocWithBinding.xaml");
doc.DataContext = new DataClass { Text = "Hello, World." };
rtb.Document = doc;
}
private static FlowDocument LoadFlowDocument(string path)
{
using (var xamlFile = new FileStream(path, FileMode.Open, FileAccess.Read))
{
return XamlReader.Load(xamlFile) as FlowDocument;
}
}
EDIT尽管您能够成功地将FlowDocument放入FlowDocumentScrollViewer中,但将此查看器同步渲染到RenderTargetBitmap中似乎不会创建所需的输出。感觉绑定尚未建立,因为文档中的硬编码文本将同步呈现。
我尝试了一些方法,但在渲染到位图之前,我似乎无法避免添加短延迟。我通过使FlowDoc2Image
方法异步并调用await Task.Delay(100)
来实现这一点。这是一个破解,但它创建了PNG。
private async Task FlowDoc2Image(
FlowDocument document, DataClass dataContext, Stream imageStream)
{
var flowDocumentScrollViewer = new FlowDocumentScrollViewer
{
VerticalScrollBarVisibility = ScrollBarVisibility.Hidden,
HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden,
Document = document,
DataContext = dataContext,
};
flowDocumentScrollViewer.Measure(
new Size(double.PositiveInfinity, double.PositiveInfinity));
flowDocumentScrollViewer.Arrange(new Rect(flowDocumentScrollViewer.DesiredSize));
await Task.Delay(100);
var renderTargetBitmap = new RenderTargetBitmap(
(int)flowDocumentScrollViewer.DesiredSize.Width,
(int)flowDocumentScrollViewer.DesiredSize.Height,
96, 96, PixelFormats.Default);
renderTargetBitmap.Render(flowDocumentScrollViewer);
var pngEncoder = new PngBitmapEncoder { Interlace = PngInterlaceOption.On };
pngEncoder.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
pngEncoder.Save(imageStream);
}