【问题标题】:WYSIWYG but not when printing所见即所得,但不是在打印时
【发布时间】:2011-06-28 19:07:49
【问题描述】:

我正在使用此控件Here 来托管可以绑定到列表并相应地生成行的表格,效果非常好,但是在打印到 XPS 或 PDF 时表格不会出现文件,它确实出现在 FlowDocument 上,但打印为空白,我尝试更改背景和前景的颜色但没有成功,有什么建议吗?

【问题讨论】:

  • 如果您不太担心沉没成本,我会考虑切换到 CSS,因为它允许打印模板。
  • @Gregory:不确定在 WPF FlowDocument 中使用 CSS 会有什么帮助。
  • 也不确定,除了这个问题真的让我很困惑,为什么打印机看不到我的表格 - 在控件内部 - 并且可以看到没有问题的其他控件

标签: .net wpf printing flowdocument


【解决方案1】:

我刚刚成功实现了该示例 (Create Flexible UIs With Flow Documents And Data Binding),并且遇到了与您相同的问题。

问题是BindableRunDataContext 设置不正确。如文章中所述,您需要修复上下文(使用FixupDataContext 辅助方法),为FrameworkContentElement 设置DataContext,并清除您之前“修复”的上下文(使用@987654327 @辅助方法)。 这些语句的执行顺序很关键。重新阅读文章并确保您理解它;我不得不重新阅读它几次并研究代码以真正理解他在说什么。

我已将实现更进一步,并在TableCell 中添加了对数据绑定其他元素的支持。更改包括使用附加属性来识别具有DataContext“固定”的元素,然后扩展辅助方法以除FrameworkContentElements 之外还针对FrameworkElements

HTH,

编辑:

public static class DataContextHelper
{

    #region UseAncestorDataContext

    public static readonly DependencyProperty UseAncestorDataContextProperty = DependencyProperty.RegisterAttached("UseAncestorDataContext", typeof(bool), typeof(DataContextHelper),
                                                                                    new FrameworkPropertyMetadata(false, DataContextHelper.OnUseAncestorDataContextChanged));

    public static bool GetUseAncestorDataContext(DependencyObject d)
    {
        return (bool)d.GetValue(UseAncestorDataContextProperty);
    }

    public static void SetUseAncestorDataContext(DependencyObject d, bool value)
    {
        d.SetValue(UseAncestorDataContextProperty, value);
    }

    private static void OnUseAncestorDataContextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if ((bool)e.NewValue)
            UseAncestorDataContext(d);
    }

    #endregion

    /// <summary>
    /// If you use a Bindable flow document element more than once, you may encounter a "Collection was modified" 
    /// exception. The error occurs when the binding is updated because of a change to an inherited dependency 
    /// property. The most common scenario is when the inherited DataContext changes. It appears that an inherited 
    /// properly like DataContext is propagated to its descendants. When the enumeration of descendants gets to 
    /// a Bindable, the dependency properties of that element change according to the new DataContext, which change 
    /// the (non-dependency) properties. However, for some reason, changing the flow content invalidates the enumeration 
    /// and raises an exception.
    /// </summary>        
    public static void UseAncestorDataContext(DependencyObject element)
    {            
        if (element is FrameworkContentElement)
        {
            FrameworkContentElement contentElement = (FrameworkContentElement)element;
            Binding binding = new Binding(FrameworkContentElement.DataContextProperty.Name);
            binding.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(FrameworkElement), 1);
            contentElement.SetBinding(FrameworkContentElement.DataContextProperty, binding);
        }
        else if (element is FrameworkElement)
        {
            FrameworkElement frameworkElement = (FrameworkElement)element;
            Binding binding = new Binding(FrameworkElement.DataContextProperty.Name);
            binding.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(FrameworkElement), 1);
            frameworkElement.SetBinding(FrameworkContentElement.DataContextProperty, binding);
        }
    }

    public static void ClearDataContextBinding(DependencyObject d)
    {
        while (RestoreDataContextRecursive(d));            
    }

    private static bool RestoreDataContextRecursive(DependencyObject d)
    {            
        if (d is FrameworkContentElement && GetUseAncestorDataContext(d))
        {
            Binding binding = BindingOperations.GetBinding(d, FrameworkContentElement.DataContextProperty);
            if (binding != null && binding.Path != null && binding.Path.Path == FrameworkContentElement.DataContextProperty.Name
                && binding.RelativeSource != null && binding.RelativeSource.Mode == RelativeSourceMode.FindAncestor && binding.RelativeSource.AncestorType == typeof(FrameworkElement) && binding.RelativeSource.AncestorLevel == 1)
            {
                BindingOperations.ClearBinding(d, FrameworkContentElement.DataContextProperty);
                return true;
            }
        }
        else if (d is FrameworkElement && GetUseAncestorDataContext(d))
        {
            Binding binding = BindingOperations.GetBinding(d, FrameworkElement.DataContextProperty);
            if (binding != null && binding.Path != null && binding.Path.Path == FrameworkElement.DataContextProperty.Name
                && binding.RelativeSource != null && binding.RelativeSource.Mode == RelativeSourceMode.FindAncestor && binding.RelativeSource.AncestorType == typeof(FrameworkElement) && binding.RelativeSource.AncestorLevel == 1)
            {
                BindingOperations.ClearBinding(d, FrameworkElement.DataContextProperty);
                return true;
            }
        }

        // As soon as we have disconnected a binding, return. Don't continue the enumeration, since the collection may have changed
        foreach (object child in LogicalTreeHelper.GetChildren(d))
        {
            if (child is DependencyObject && RestoreDataContextRecursive((DependencyObject)child))
                return true;
        }

        return false;
    }

}

用法

 <DataTemplate x:Key="PercentCellTemplate">
        <documents:ContentFragment>
            <TableCell Style="{StaticResource TableCellStyle}" BorderThickness="0,0,1,0"> 
                <Paragraph>
                    <Rectangle Width="14" Height="14" VerticalAlignment="Center" Margin="0,6,0,0" Fill="{Binding Path=Result, Mode=OneWay, Converter={StaticResource MappingConverterResultEnumToIconResource}}" 
                               documents:DataContextHelper.UseAncestorDataContext="True"/>
                    <documents:DocumentRun Style="{StaticResource ReportDocument_NormalRunStyle}" Text="{Binding Path=Percent, Mode=OneWay, StringFormat={}{0:0.000}%}" 
                                           BaselineAlignment="Center" documents:DataContextHelper.UseAncestorDataContext="True" />
                </Paragraph>
            </TableCell>
        </documents:ContentFragment>
    </DataTemplate>

【讨论】:

  • 感谢您回到这里,我不知道为什么我没有解决它,因为我解决了这个问题,是的,确实是数据上下文,我认为他们应该在下一个 . NET 版本
  • 不客气。那里明显缺乏用于生成/打印流程文档的解决方案,因此在花了一周时间为自己弄清楚之后,我可以回馈的任何一点都是为了更大的利益。我刚刚编辑了答案以包含我的帮助方法版本,它还修复了FrameworkElements 上的绑定。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-21
  • 2015-09-10
  • 2011-07-18
  • 2017-08-21
相关资源
最近更新 更多