【问题标题】:handler is invalid in a BitmapEncoder.Frames.Add call处理程序在 BitmapEncoder.Frames.Add 调用中无效
【发布时间】:2018-06-12 00:19:21
【问题描述】:

我正在使用这种自定义方法将 Bitmapsource 转换为 Bitmap:

    public Bitmap BitmapFromSource(BitmapSource bitmapsource) {
        using (MemoryStream outStream = new MemoryStream()) {
            BitmapEncoder enc = new BmpBitmapEncoder();
            enc.Frames.Add(BitmapFrame.Create(bitmapsource));
            enc.Save(outStream);
            using (var tempBitmap = new Bitmap(outStream)) {
                return new Bitmap(tempBitmap);
            } } }

这个方法在我的代码中被调用了好几次,效果很好。 但是当我使用鼠标单击事件或按键事件调用它时,我得到处理程序无效错误。

我不知道如何继续。有什么建议吗?

在代码中我有一个位帧列表:

List<BitmapFrame> myImages = new List<BitmapFrame>();

最初,当我将每一帧显示到几个图片框时,该方法有效:

var handler = new EventHandler(pictureBoxClick);

for (int i = 0; i < (decoder.Frames.Count); i++) {
   var picture = new MyPictureBox {
    Name = "pictureBoxFrame" + i,
    Width = (int)newWidth,
    Height = (int)newHeight,
    SizeMode = PictureBoxSizeMode.Zoom,
    Location= loc,
    Image = BitmapFromSource(myImages[i]), };
Controls[i].Click += handler;
splitContainer1.Panel1.Controls.Add(picture);
}

然后当我单击这些图片框之一时:

void pictureBoxClick (object sender , EventArgs e) {
    var selectedPictureBox = (PictureBox)sender;
    int idx = Controls.IndexOf(selectedPictureBox);
    pictureBox1.Image = BitmapFromSource(myImages[idx]);
}

我得到了错误...

【问题讨论】:

  • 然后您应该发布负责传递(可能有错误)BitmapSource 的代码。
  • 您说这个方法是从多个事件处理程序中调用的。当然,可以调试这些事件中的代码。在那里设置一个断点并查看传递给BitmapFromSource() 方法的内容。因此,您有机会检查您的 List&lt;BitmapFrame&gt; 并查看它实际包含的内容。如果您发布该代码,就会更容易理解可能出了什么问题。
  • 我看不到您将 pictureBoxClick 处理程序分配给 PictureBox 控件的 Click 事件的位置。 int idx = Controls.IndexOf(selectedPictureBox);List&lt;BitmapFrame&gt; 索引和 Form.Controls 数组内的 PictureBox 控件位置之间没有可靠的关系。另外,你不需要它。您可以: 1) 将List&lt;BitmapFrame&gt; 索引分配给构造函数中PB 控件的Tag 属性。 2)直接分配pictureBox1.Image = (Image)selectedPictureBox.Image.Clone()。无论如何,您应该在使用之前检查myImages[idx]的内容..
  • 我添加了事件处理程序。我不介意 'code' List 'code' 索引和 PictureBox 控件在 'code' Form.Controls'code' 数组中的位置之间的关系。每一帧的内容可能会发生变化,所以软件需要重新加载并重新显示所有帧
  • 看看我发的能不能用。测试用的sample Form可以从PasteBin下载。

标签: c# bitmapsource


【解决方案1】:

从我从您的代码中可以看出,您很可能是“流”的受害者。
这意味着,当您从 FileStream 加载资源时,该流必须在该资源的生命周期内可用(未释放)。
这也适用于 BitmapDecoder 引用的图像资源。
如果您处理用于初始化 BitmapDecoder 的流,它的 Frames 集合将设置为 1x1 大小的 1 帧。
由于保持流打开不是一个好主意,因此通常将其复制到 MemoryStream(原始字节数组)并在之后立即处理。

无论您读过或听过什么,MemoryStream 并不真正需要 被处理(至少不是立即处理),因为它并没有真正使用 任何重要资源。

从流中加载图像资源后,BitmapDecoder 可以这样初始化:

MemoryStream memstream = new MemoryStream();
stream.CopyTo(memstream);
memstream.Position = 0;
BitmapDecoder bitmapDecoder = BitmapDecoder.Create(memstream,
                                            BitmapCreateOptions.PreservePixelFormat,
                                            BitmapCacheOption.Default);

这样,BitmapDecoderBitmapFrames 将有一个有效的句柄,因为底层流仍然存在。
当您加载新图像时,MemoryStream 将使用新的FileStream 进行更新。

为了测试这里和 cmets 中所写内容的结果(这些建议也很相关),我构建了一个测试表单类。
您可以在 PasteBin 中download the source code

【讨论】:

  • 是的,我从流中加载资源,但我还将位图复制到新位图中,以便在关闭流之前将其返回。而且,我可以在代码中使用这种方法上千次没有问题。
  • @Federico Bianchi 您的BitmapFromSource() 不是问题(如果您下载了我发布的代码,您会看到我使用了 +- 相同的方法)。当您尝试分配位图 → pictureBox1.Image = BitmapFromSource(myImages[idx]); 时,List&lt;BitmapFrame&gt; 持有无效的帧句柄。由于您使用BitmapDecoder 帧→for (int i = 0; i &lt; (decoder.Frames.Count); i++) 然后Image = BitmapFromSource(myImages[i]) 创建初始图像,因此这些帧在其他地方变得无效。另外,您指的是不可靠的索引int idx = Controls.IndexOf(...)
  • @Federico Bianchi 我看不出两者之间发生了什么,但你得到的错误清楚地表明句柄无效。发生这种情况的原因是 a 写的。您可以发布整个过程,以便对其进行测试以找出发生这种情况的位置和原因。
  • 在您的代码中,您没有使用 List 您将图像从另一个图片框加载到图片框。您不会使用相同的代码。
  • @Federico Bianchi 因为不需要。但是您可以将图像分配:pictureBox1.Image = this.CurrentBitmap; 替换为:pictureBox1.Image = BitmapFromSource(this.Decoder.Frames[this.CurrentSelectedFrame]);,您将得到相同的结果,因为BitmapFrames 的列表仍然是BitmapDecoder 的一部分,它(出于已经说过的原因)引用有效的句柄。而Frame Index存储在PictureBoxobjects Tag中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-21
  • 2019-05-20
相关资源
最近更新 更多