【问题标题】:XAML WPF How to add inline background image on FlowDocument?XAML WPF 如何在 FlowDocument 上添加内联背景图像?
【发布时间】:2014-10-22 20:27:32
【问题描述】:

下面的代码是给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>

【问题讨论】:

  • 也许您可以从ImageSource 派生(BitmapImage 可能更接近)并实现您自己的解码逻辑。
  • stackoverflow.com/questions/13529301/…可以将Source设置为BitmapImage
  • @eranotzap 你有代码示例吗?我需要将字符串嵌入到 xaml 文档中,而不需要后面的代码。

标签: c# wpf xaml


【解决方案1】:

您可以通过以下机制(桌面 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)可以解决此问题。

【讨论】:

  • 您的转换器工作正常。为此+1。我可以将字符串存储在字典中,并在绑定 ImageSource 时直接使用转换器。
【解决方案2】:

经过多次提炼,这里是最简单的添加内嵌背景图片的方法。感谢@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 绑定。

【讨论】:

    【解决方案3】:

    根据文档,ImageBrush 类是密封的,不能扩展。文档说,如果 ImageBrush 无法加载 ImageSource,则会调用 ImageBrush.ImageFailed 事件。请看这里:Documentation

    您可以像这样在 XAML 中注册您的处理程序:&lt;ImageBrush ImageFailed="eventhandler"/&gt; 您的处理程序只需要读取 ImageBrush.ImageSource 的值,将字符串解析为 BitmapImage 对象,如another question 中所示,并将 BitmapImage 对象设置为 ImageSource,如下所示:yourImageBrush.ImageSource=Base64StringToBitmap(ImageBrush.ImageSource.GetValue.ToString())

    【讨论】:

    • 错误信息:无法设置未知成员'System.Windows.Media.ImageBrush.ImageFailed'
    猜你喜欢
    • 1970-01-01
    • 2019-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-21
    • 1970-01-01
    • 1970-01-01
    • 2013-07-29
    相关资源
    最近更新 更多