XAML WPF如何在FlowDocument上添加内联背景图像

本文关键字:添加 背景 图像 FlowDocument WPF XAML | 更新日期: 2023-09-27 18:19:58

以下代码用于将背景图像添加到Flow Document

<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
  <FlowDocument.Background>
    <ImageBrush ImageSource="C:'licorice.jpg" />
  </FlowDocument.Background>
  <Paragraph>
    <Run>Hello World!</Run>
  </Paragraph>
</FlowDocument>

问题是,如何更改ImageSource,使其将图像数据存储为xaml文件上的字符串?ImageBrush是密封的,所以我无法从中派生。我正在寻找这样的东西:

<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
  <FlowDocument.Background>
    <InlineImageBrush base64Source="iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCA..." /> <!--does not work-->
  </FlowDocument.Background>
  <Paragraph>
    <Run>Hello World!</Run>
  </Paragraph>
</FlowDocument>

XAML WPF如何在FlowDocument上添加内联背景图像

您可以通过以下机制(桌面WPF)做到这一点:

  1. 创建一个自定义的DependencyObject子类,其中包含一个DependencyProperty(基本64图像字符串)。给你的班级打电话,例如ImageData。完成此操作后,您可以将该类的命名实例添加到FlowDocument.ResourcesWindow.Resources(或Grid.Resources或其他)中,并在XAML中直接初始化base64字符串。

  2. 创建一个自定义的IValueConverter,将base64字符串转换为BitmapImage。将其作为命名静态资源添加到Window.Resources中。

  3. 对于要用作流文档背景的每个图像,请向流文档本身的静态资源或更高级别的控件(如窗口)添加一个ImageData。(注意——在我的旧版本Visual Studio中,如果将图像资源添加到流文档中,表单设计者会感到困惑。尽管如此,应用程序还是成功编译并运行了。)

  4. 最后,为Background.ImageBrush.ImageSource添加一个DataBinding,将其链接到命名的ImageData资源的基64字符串属性,并使用自定义转换器将其转换为图像。

详情如下。首先,自定义ImageData类非常简单:

public class ImageData : DependencyObject
{
    public static readonly DependencyProperty Base64ImageDataProperty =
        DependencyProperty.Register("Base64ImageData",
        typeof(string),
        typeof(ImageData));
    public string Base64ImageData
    {
        get { return (string)(GetValue(Base64ImageDataProperty)); }
        set { SetValue(Base64ImageDataProperty, value); }
    }
}

接下来,自定义转换器和一些辅助实用程序:

public class Base64ImageConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        string base64String = value as string;
        if (base64String == null)
            return null;
        return ImageHelper.Base64StringToBitmapImage(base64String);
    }
    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
public static class ImageHelper
{
    public static BitmapImage Base64StringToBitmapImage(string base64String)
    {
        BitmapImage bitmapImage = new BitmapImage();
        bitmapImage.BeginInit();
        bitmapImage.StreamSource = new MemoryStream(Convert.FromBase64String(base64String));
        bitmapImage.EndInit();
        return bitmapImage;
    }
    public static string FileToBase64String(string filename)
    {
        using (var stream = File.Open(filename, FileMode.Open))
        using (var reader = new BinaryReader(stream))
        {
            byte[] allData = reader.ReadBytes((int)reader.BaseStream.Length);
            return Convert.ToBase64String(allData);
        }
    }
}

将其放置在窗口、应用程序或其他方便您并可在整个应用程序中重复使用的中心位置的静态资源中:

<Window x:Class="RichTextBoxInputPanel.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:w="clr-namespace:RichTextBoxInputPanel" 
    Title="RichTextBoxInputPanel" Height="600" Width="1200" Loaded="Window_Loaded">
    <Window.Resources>
        <w:Base64ImageConverter x:Key="Base64ImageConverter"></w:Base64ImageConverter>
    </Window.Resources>

您还可以将其添加到流文档本身的静态资源中,并将其与下面显示的ImageData一起添加。

现在,在流文档的资源中添加一个ImageData

            <FlowDocument >
                <FlowDocument.Resources>
                    <w:ImageData x:Key="DocumentBackground" Base64ImageData="iVBORw0K...etc etc">
                    </w:ImageData>
                </FlowDocument.Resources>

最后,添加后台的绑定属性:

               <FlowDocument.Background>
                    <ImageBrush>
                        <ImageBrush.ImageSource>
                            <Binding Converter="{StaticResource Base64ImageConverter}" 
                                     Source="{StaticResource DocumentBackground}"
                                     Path="Base64ImageData" Mode="OneWay"></Binding>
                        </ImageBrush.ImageSource>
                    </ImageBrush>
                </FlowDocument.Background>

最后,正如我上面提到的,将静态ImageData资源放在流文档本身上会导致WPF表单设计器(在VS2008上)抛出一个虚假错误。尽管出现了错误,应用程序还是成功编译并运行。将ImageData静态资源从流文档移动到更高的控件(如包含它的RichTextBox或FlowDocumentReader)可以解决此问题。

经过多次细化后,这里是添加内联背景图像的最简单方法。感谢@dbc的转换器。

<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:ns1="MyProject;assembly=MyProject"
              xmlns:system="clr-namespace:System;assembly=mscorlib"
              >
  <FlowDocument.Resources>
        <ns1:Base64ImageConverter x:Key="base64ImageConverter" ></ns1:Base64ImageConverter>
        <system:String x:Key="backgroundImage">/9j/4AAQSkZJRgABAQAAAQAB...</system:String>
  </FlowDocument.Resources>
  <FlowDocument.Background>
    <ImageBrush>
        <ImageBrush.ImageSource>
            <Binding Converter="{StaticResource base64ImageConverter}" 
                     Source="{StaticResource backgroundImage}"
                     Mode="OneWay"></Binding>
        </ImageBrush.ImageSource>
    </ImageBrush>
  </FlowDocument.Background>
  <Paragraph>
    <Run>Hello World!</Run>
  </Paragraph>
</FlowDocument>

这是转换器

using System;
using System.IO;
using System.Windows.Data;
using System.Windows.Media.Imaging;
namespace MyProject
{
    public class Base64ImageConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            string base64String = value as string;
            if (base64String == null)
                return null;
            BitmapImage bitmapImage = new BitmapImage();
            bitmapImage.BeginInit();
            bitmapImage.StreamSource = new MemoryStream(System.Convert.FromBase64String(base64String));
            bitmapImage.EndInit();
            return bitmapImage;
        }
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

它只适用于这两段代码。是的,您可以将system:String与Mode=OneWay绑定。

根据文档,ImageBrush类是密封的,不能扩展。文档指出,如果ImageBrush未能加载ImageSource,则会调用ImageBrush.ImageFailed事件。请参阅此处:文档

您可以在XAML中注册处理程序,如下所示:<ImageBrush ImageFailed="eventhandler"/>您的处理程序只需要读取ImageBrush.ImageSource的值,将String解析为BitmapImage对象,如另一个问题中所示,并将BitmapImage设置为ImageSource,如yourImageBrush.ImageSource=Base64StringToBitmap(ImageBrush.ImageSource.GetValue.ToString())