本文介绍了在运行时创建CroppedBitmap-不会从资源加载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

限时删除!!

我正在尝试编写代码,该代码将从资源中加载图片,然后对其进行裁剪。当我在XAML中全部或部分执行此代码时,此代码将起作用。我想从全XAML切换到全代码,因此我可以使用不同的Uris在一个地方重复使用。

I'm trying to write code that will load an image from a resource, and then crop it. This code works when I do all, or part, of it in XAML. I want to switch from all-XAML to all-code, so I can reuse this more than one place, with different Uris.

但是当我尝试执行相同操作时在代码中,我得到了DirectoryNotFoundException,因为它突然开始尝试在磁盘上查找文件夹,而不是从资源中加载图像。

But when I try to do the same thing in code, I get a DirectoryNotFoundException, because suddenly it starts trying to look for a folder on disk, instead of loading the image from the resource.


  • 如果我在XAML中加载BitmapImage,然后在XAML中创建一个CroppedBitmap,则一切正常。

  • 如果我在XAML中加载BitmapImage,然后编写代码以从中创建CroppedBitmap

  • 如果我将BitmapImage加载到代码中,则从中创建CroppedBitmap,一切正常。

  • 但是如果我在代码中加载BitmapImage并在代码中创建一个CroppedBitmap,它将尝试从文件系统而不是资源中加载,并且我得到DirectoryNotFoundException。

  • If I load the BitmapImage in XAML, and then create a CroppedBitmap in XAML, everything works.
  • If I load the BitmapImage in XAML, and then write code to create a CroppedBitmap from it, everything works.
  • If I load the BitmapImage in code, without creating a CroppedBitmap from it, everything works.
  • But if I load the BitmapImage in code and create a CroppedBitmap in code, it tries to load from the filesystem instead of the resources, and I get a DirectoryNotFoundException.

代码示例如下。我确定我做某件事很愚蠢,但是现在我已经经历了整整三遍了(一次在我的真实应用程序中,一次在测试应用程序中,一次在编写此问题时),并且我得到了相同的结果对所有三个代码都返回结果。

Code samples are below. I'm sure I'm doing something stupid, but I've run through the whole thing three times now (once in my real app, once in a test app, and once while writing up this question), and I got the same results all three times.

对于以下所有代码示例,我都在项目内部创建了一个Images文件夹,并在其中添加了一个现有的图片,称为 elf.png ,其属性设置为默认值(生成操作=资源;复制到输出目录=不复制)。

For all of the following code samples, I've created an Images folder inside my project, and added an existing image there called "elf.png", with properties set to defaults (Build Action = "Resource"; Copy to Output Directory = "Do not copy").

案例1:XAML中的BitmapImage和CroppedBitmap。

Case 1: Both BitmapImage and CroppedBitmap in XAML.

<Window x:Class="WpfApplication8.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="300" Width="300">
    <Window.Resources>
        <BitmapImage x:Key="fullImage" UriSource="Images/elf.png"/>
        <CroppedBitmap x:Key="croppedImage" Source="{StaticResource fullImage}"
                       SourceRect="0 0 240 320"/>
    </Window.Resources>
    <Image Source="{StaticResource croppedImage}"/>
</Window>

这显示了位图的裁剪部分,如预期的那样。

This shows the cropped portion of the bitmap, as expected.

XAML:

<Window x:Class="WpfApplication8.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="300" Width="300">
    <Window.Resources>
        <BitmapImage x:Key="fullImage" UriSource="Images/elf.png"/>
    </Window.Resources>
    <Image Name="image"/>
</Window>

代码隐藏的构造函数:

public Window1()
{
    InitializeComponent();
    var fullImage = (BitmapImage) FindResource("fullImage");
    var croppedImage =
        new CroppedBitmap(fullImage, new Int32Rect(0, 0, 240, 320));
    image.Source = croppedImage;
}

这也显示了预期的位图裁剪部分。

This also shows the cropped portion of the bitmap, as expected.

案例3:代码中的BitmapImage;

Case 3: BitmapImage in code; no CroppedBitmap.

public Window1()
{
    InitializeComponent();
    var uri = new Uri("Images/elf.png", UriKind.RelativeOrAbsolute);
    var fullImage = new BitmapImage(uri);
    image.Source = fullImage;
}

这将显示整个位图。这不是我想要的,但确实告诉我,我知道如何编写C#代码来创建正确的Uri并从资源中加载BitmapImage。

This shows the entire bitmap. This isn't what I want, but does tell me that I know how to write C# code to create the right kind of Uri and load a BitmapImage from a resource.

案例4:代码中的BitmapImage和CroppedBitmap。

Case 4: BitmapImage and CroppedBitmap in code.

    public Window1()
    {
        InitializeComponent();
        var uri = new Uri("Images/elf.png", UriKind.RelativeOrAbsolute);
        var fullImage = new BitmapImage(uri);
        var croppedImage =
            new CroppedBitmap(fullImage, new Int32Rect(0, 0, 240, 320));
        image.Source = croppedImage;
    }

据我所知,这和以前一样。它使用的代码我知道将从资源中加载BitmapImage,而我知道的代码将从加载的BitmapImage中裁剪出一部分。但是以某种方式,当将两者放在一起时,它会忘记资源在那里,而是尝试从磁盘加载。我收到以下异常:

As far as I can tell, this just puts together the same pieces as before. It uses code that I know will load a BitmapImage from a resource, and code that I know will crop a section from a loaded BitmapImage. But somehow, when the two are put together, it forgets that the resource is there, and tries to load from disk. I get the following exception:


  • XamlParseException:无法创建在程序集'WpfApplication8,Version = 1.0.0.0中定义的'Window1'实例, 文化=中性,PublicKeyToken =空'。调用的目标引发了异常。标记文件'Window1.xaml'第1行位置13出错。


    • 内部异常: TargetInvocationException:调用的目标抛出了异常。


      • 内部异常: DirectoryNotFoundException:找不到路径'C:\svn\WpfApplication8\的一部分 WpfApplication8\bin\Debug\Images\elf.png'。

      • XamlParseException: "Cannot create instance of 'Window1' defined in assembly 'WpfApplication8, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. Exception has been thrown by the target of an invocation. Error in markup file 'Window1.xaml' Line 1 Position 13."
        • Inner exception: TargetInvocationException: "Exception has been thrown by the target of an invocation."
          • Inner exception: DirectoryNotFoundException: "Could not find a part of the path 'C:\svn\WpfApplication8\WpfApplication8\bin\Debug\Images\elf.png'."

          内部异常异常堆栈跟踪显示,实例化CroppedBitmap的行引发了原始异常(DirectoryNotFoundException)。我不知道为什么该行会尝试从磁盘读取数据,或者当我可以告诉等效的XAML正常工作时为什么它行不通。

          The inner-inner-exception stack trace shows that the original exception (the DirectoryNotFoundException) is being thrown by the line that instantiates the CroppedBitmap. I don't know why that line would be trying to read from disk, or why it doesn't work when the as-far-as-I-can-tell-equivalent XAML works fine.

          由于我知道XAML使用的是无参数构造函数,因此我也尝试了以下版本,该版本应与XAML实际工作更接近:

          Since I know the XAML is using the parameterless constructors, I also tried the following version, which should be much closer to what the XAML actually does:

          public Window1()
          {
              InitializeComponent();
              var uri = new Uri("Images/elf.png", UriKind.RelativeOrAbsolute);
              var fullImage = new BitmapImage();
              fullImage.BeginInit();
              fullImage.UriSource = uri;
              fullImage.EndInit();
              var croppedImage = new CroppedBitmap();
              croppedImage.BeginInit();
              croppedImage.Source = fullImage;
              croppedImage.SourceRect = new Int32Rect(0, 0, 240, 320);
              croppedImage.EndInit();
              image.Source = croppedImage;
          }
          

          这次是来自 croppedImage.EndInit的例外(); 行。

          关于如何获取全代码版本以正确加载资源并裁剪图像的任何想法? XAML版本中发生了什么不同?

          Any ideas on how I can get the all-code version to correctly load the resource and crop the image? What's happening in the XAML version that's different?

          推荐答案

          魔术竟然是在BitmapImage的 BaseUri 中>属性。 BaseUri显然是UriSource相对的当前目录。

          The magic turned out to be in the BitmapImage's BaseUri property. BaseUri apparently serves as the "current directory" that UriSource is relative to.

          当从XAML加载BitmapImage时,BaseUri被神奇地设置为 pack://。 application:,, / WpfApplication8; component / window1.xaml。当我在创建CroppedBitmap之前修改了代码片段#4来将fullImage.BaseUri显式设置为相同的值时,一切正常。

          When my BitmapImage was being loaded from XAML, BaseUri was being magically set to "pack://application:,,,/WpfApplication8;component/window1.xaml". When I modified code snippet #4 to explicitly set fullImage.BaseUri to that same value before creating the CroppedBitmap, everything worked.

          为什么它可以从XAML运行 (以及来自Just-BitmapImage-without-CroppedBitmap)

          那么这个神奇的BaseUri值是从哪里来的?

          So where did this magic BaseUri value come from?

          BaseUri是接口。 IUriContext.BaseUri在WPF程序集中的两个位置设置,在我的各个示例之间,我设法都击中了它们。难怪我很困惑。

          BaseUri is part of the IUriContext interface. IUriContext.BaseUri is set in two places in the WPF assemblies, and between my various examples, I managed to hit both of them. No wonder I was confused.


          • BamlRecordReader.ElementInitialize。 BAML加载器在加载元素时会自动设置BaseUri。实现IUriContext。这解释了为什么我的示例#1和#2起作用的原因:它们是从编译后的BAML资源加载的。

          • Image.UpdateBaseUri (只要Source属性发生更改,就会调用)。这将检查Source是否实现IUriContext,如果是,则设置其BaseUri。这解释了我的示例#3为何起作用的原因:将BitmapImage推入GUI强制其获得正确的搜索路径。

          • BamlRecordReader.ElementInitialize. The BAML loader automatically sets BaseUri anytime it loads an element that implements IUriContext. This explains why my examples #1 and #2 worked: they were loading from the compiled BAML resource.
          • Image.UpdateBaseUri (called whenever the Source property is changed). This checks to see if the Source implements IUriContext, and if so, sets its BaseUri. This explains why my example #3 worked: pushing the BitmapImage into the GUI forced it to get the right search path.

          当BaseUri设置为magic pack:// URI时,在EXE资源中获取图像。否则(仅当在代码中创建所有内容而不将其推送到GUI中时发生),它只会在磁盘上显示。

          It only looks for the image in the EXE resources when BaseUri is set to the magic pack:// URI. Without that (as happens when everything is created in code and not pushed into the GUI), it only looks on disk.

          修复

          如上所述,我可以对BaseUri进行硬编码。但是 BaseUriHelper 类提供了更好的解决方案:

          As noted above, I could hard-code BaseUri. But the BaseUriHelper class provides a better fix:

          fullImage.BaseUri = BaseUriHelper.GetBaseUri(this);
          

          这会将fullImage设置为与窗口具有相同的BaseUri()。如果在创建CroppedBitmap之前完成此操作,则一切正常。

          This sets fullImage to have the same BaseUri as the window (this). If this is done before creating the CroppedBitmap, everything works.

          这篇关于在运行时创建CroppedBitmap-不会从资源加载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

          1403页,肝出来的..

09-07 01:24