简体   繁体   English

在Windows中绑定Image.Source到String?

[英]Binding Image.Source to String in WPF?

I have below XAML code : 我有以下XAML代码:

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    DataContext="{Binding RelativeSource={RelativeSource Self}}"
    WindowStartupLocation="CenterScreen"
    Title="Window1" Height="300" Width="300">

    <Grid>
        <Image x:Name="TestImage" Source="{Binding Path=ImageSource}" />
    </Grid>

</Window>

Also, there is a method that makes an Image from a Base64 string : 此外,还有一种方法可以从Base64字符串生成图像:

Image Base64StringToImage(string base64ImageString)
{
    try
    {
        byte[] b;
        b = Convert.FromBase64String(base64ImageString);
        MemoryStream ms = new System.IO.MemoryStream(b);
        System.Drawing.Image img = System.Drawing.Image.FromStream(ms);

        //////////////////////////////////////////////
        //convert System.Drawing.Image to WPF image
        System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(img);
        IntPtr hBitmap = bmp.GetHbitmap();
        System.Windows.Media.ImageSource imageSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(hBitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());

        Image wpfImage = new Image();
        wpfImage.Source = imageSource;
        wpfImage.Width = wpfImage.Height = 16;
        //////////////////////////////////////////////

        return wpfImage;
    }
    catch
    {
        Image img1 = new Image();
        img1.Source = new BitmapImage(new Uri(@"/passwordManager;component/images/TreeView/empty-bookmark.png", UriKind.Relative));
        img1.Width = img1.Height = 16;
        return img1;
    }
} 

Now, I'm gonna bind TestImage to the output of Base64StringToImage method. 现在,我TestImage绑定到Base64StringToImage方法的输出。
I've used the following way : 我使用了以下方式:

public string ImageSource { get; set; }
ImageSource = Base64StringToImage("iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAABjUExURXK45////6fT8PX6/bTZ8onE643F7Pf7/pDH7PP5/dns+b7e9MPh9Xq86NHo947G7Hm76NTp+PL4/bHY8ojD67rc85bK7b3e9MTh9dLo97vd8/D3/Hy96Xe76Nfr+H+/6f///1bvXooAAAAhdFJOU///////////////////////////////////////////AJ/B0CEAAACHSURBVHjaXI/ZFoMgEEMzLCqg1q37Yv//KxvAlh7zMuQeyAS8d8I2z8PT/AMDShWQfCYJHL0FmlcXSQTGi7NNLSMwR2BQaXE1IfAguPFx5UQmeqwEHSfviz7w0BIMyU86khBDZ8DLfWHOGPJahe66MKe/fIupXKst1VXxW/VgT/3utz99BBgA4P0So6hyl+QAAAAASUVORK5CYIII").Source.ToString(); 

but nothing happen. 但什么都没发生。
How can I fix it ? 我该如何解决?

BTW, I'm dead sure that the base64 string is correct 顺便说一下,我确定base64字符串是正确的

Let's break down what you're doing. 让我们分解你正在做的事情。

<Image Source="{Binding ImageSource}" />

For this to work, the binding source needs to be either an ImageSource, or a string representing a URI to an image file. 为此,绑定源需要是ImageSource,或者是表示图像文件的URI的字符串。 So let's take a look at what the ImageSource property actually is. 那么让我们来看看ImageSource属性实际上是什么。

public string ImageSource { get; set; }

One problem here is that ImageSource isn't raising PropertyChanged events. 这里的一个问题是ImageSource没有引发PropertyChanged事件。 So WPF won't update the binding target when you update the property. 因此,更新属性时WPF不会更新绑定目标。

But also, ImageSource isn't an ImageSource, it's a string. 而且,ImageSource不是ImageSource,它是一个字符串。 That's okay, but WPF is going to interpret that string as a URI. 没关系,但WPF会将该字符串解释为URI。 What is that URI? 什么是URI?

ImageSource = Base64StringToImage(BIG_HONKING_STRING).Source.ToString(); 

This is the nub of your problem. 这是你问题的核心。 The ImageSource string isn't actually a URI, because your image isn't an addressable resource. ImageSource字符串实际上不是URI,因为您的图像不是可寻址资源。 Base64StringToImage creates an in-memory ImageSource from the base64 string, then return an Image with that as its Source. Base64StringToImage从base64字符串创建一个内存中的ImageSource,然后返回一个Image作为其Source。 Then you take the Image's Source (which is an ImageSource object), and stringise that. 然后你获取Image的Source(它是一个ImageSource对象),并将其串联。 That might work if the ImageSource had come from a file or URL, but it didn't: it came from a HBITMAP. 如果ImageSource来自文件或URL,那可能会有效,但它没有:它来自HBITMAP。 So the result of ToString() is going to be meaningless. 所以ToString()的结果将毫无意义。 So ImageSource is being set to something meaningless, and your Image is trying to interpret this meaningless thing as the URL of a bitmap file. 所以ImageSource被设置为无意义的东西,你的Image试图将这个毫无意义的东西解释为位图文件的URL。

So to fix this you need to do three things: 所以要解决这个问题,你需要做三件事:

  1. Raise the PropertyChanged event for the ImageSource property (or make it a dependency property). 为ImageSource属性引发PropertyChanged事件(或使其成为依赖项属性)。
  2. Change the ImageSource property to be of type ImageSource instead of type string (so that it can contain URL-less image sources). 将ImageSource属性更改为ImageSource类型而不是string类型(以便它可以包含无URL图像源)。
  3. Change your setter call to set ImageSource to Base64StringToImage(...).Source -- ie remove the ToString() call. 更改你的setter调用,将ImageSource设置为Base64StringToImage(...).Source - 即删除ToString()调用。 Better still, change Base64StringToImage to return an ImageSource rather than an Image: creating an Image element just creates overhead because all you're really interested in is the BitmapSource. 更好的是,更改Base64StringToImage以返回ImageSource而不是Image:创建一个Image元素只会产生开销,因为你真正感兴趣的是BitmapSource。

As a complement to @itowlson's excellent answer, this is what your code should look like: 作为@ itowlson出色答案的补充,这就是你的代码应该是这样的:

// MainWindow.xaml
<Window x:Class="MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <DockPanel>
        <Image Source="{Binding ImageSource}" />
    </DockPanel>
</Window>

// MainWindow.xaml.cs
using System.ComponentModel;
using System.IO;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        var model = new MainModel();
        DataContext = model;

        model.SetImageData(File.ReadAllBytes(@"C:\Users\Public\Pictures\Sample Pictures\Desert.jpg"));
    }
}

class MainModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public void SetImageData(byte[] data) {
        var source = new BitmapImage();
        source.BeginInit();
        source.StreamSource = new MemoryStream(data);
        source.EndInit();

        // use public setter
        ImageSource = source;
    }

    ImageSource imageSource;
    public ImageSource ImageSource
    {
        get { return imageSource; }
        set
        {
            imageSource = value;
            OnPropertyChanged("ImageSource");
        }
    }

    protected void OnPropertyChanged(string name)
    {
        var handler = PropertyChanged;
        if (null != handler)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
}

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

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