繁体   English   中英

XAML WPF如何在FlowDocument上添加嵌入式背景图像?

[英]XAML WPF How to add inline background image on FlowDocument?

以下代码是将背景图像添加到流文档中

<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>

您可以通过以下机制(桌面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资源的base 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())

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM