【问题标题】:Do my URIs have to be so long and explicit?我的 URI 必须如此长且明确吗?
【发布时间】:2012-11-20 19:32:41
【问题描述】:

我正在使用 Microsoft Prism 和 Unity 编写一个模块化应用程序。我的应用程序的 Shell 项目加载了各种 DLL,这些 DLL 都包含它们自己的 /resources 或 /images 文件夹和用户界面视图。因此,每个模块都是一个 DLL。

当我尝试在我的应用程序中使用资源时,似乎我必须非常明确地说明它的位置才能使其正常工作。例如,要在同一模块/dll 中定位图像:

<Image Source="pack://application:,,,/MyCompany.MyProduct.MyModule;Component/Images/ZoomIn.gif" />

我真的必须每次都使用长格式的 URI 吗?我尝试过较短的版本,例如:

pack://application:,,,/Images/ZoomIn.gif

Images/ZoomIn.gif

ZoomIn.gif

等等

我认为那里的第二个版本应该可以工作。当我看到 Uri 示例时,他们经常说“相对于当前程序集”。这是正在运行的可执行程序的程序集吗?或者这是代码所属的程序集(我的库/模块)?

更新:

在 Peter Hansen 的帮助下,我能够将其缩短为:

<Image Source="../Images/ZoomOut.png" />

显然我必须使用 ../ 因为我的视图位于子文件夹中。我也可以不使用 pack:// 语法,因为类型转换器会为我执行此操作。

【问题讨论】:

    标签: wpf mvvm prism unity-container


    【解决方案1】:

    在 WPF 中检索二进制资源时有几种不同的选择,它们都取决于您想要哪种行为。

    1. 如果您的资源应该嵌入到程序集中,请将它们添加到 Visual Studio 中的项目中,并将 Build Action 设置为 Resource。这样它们将被烘焙到程序集中,因此不能轻易更改。

    2. 如果它们应该保留为松散文件,请将它们添加到项目中,并将 Build Action 设置为 Content。还要确保它们被复制到输出目录。这是一个好主意,如果您需要经常更换它们,并且不想每次都重新编译程序集。

    3. 如果您希望它们作为松散文件,但由于某种原因不想将它们包含在您的 Visual Studio 解决方案中(可能在编译时不知道它们),您可以使用完整路径或使用称为 SiteOfOrigin 表示法的东西。我不会讨论这个,因为这与你的情况无关。

    要从您的代码中访问资源,您可以使用 Pack URI,它可以有不同的形式:

    • pack://application:,,,/img.jpg
      引用项目根目录中的图像。

    • pack://application:,,,/Folder1/Folder2/img.jpg
      引用项目子文件夹中的图像。

    • pack://application:,,,/NameOfDll;Component/img.jpg
      在 Visual Studio 中引用的不同程序集中引用图像。

    幸运的是,当从 XAML 引用资源时,无需编写完整的 URI。
    基本上可以避免使用 pack://application:,,, 部分,因为存在可以为您将部分位置转换为完整 URI 的 TypeConverter。

    对于上面的第 1 点和第 2 点,相同的 XAML 用于引用资源,无论它们在执行时是作为程序集旁边的松散文件存在还是嵌入其中。

    但是,当从过程代码中引用资源时,必须使用完全定义的显式 URI。

    我已经编写了一些代码并包含了一些图像,以展示它是如何工作的。

    相关 XAML:

    <StackPanel>
        <TextBlock Text="Embedded in same assembly" />
        <Image Source="gift.png" />
    </StackPanel>
    
    <StackPanel>
        <TextBlock Text="Embedded in same assembly in a subfolder" />
        <Image Source="Content/Images/gift.png" />
    </StackPanel>
    
    <StackPanel>
        <TextBlock Text="Embedded in same assembly in a subfolder using full pack URI format" />
        <Image Source="pack://application:,,,/Content/Images/gift.png" />
    </StackPanel>
    
    <StackPanel>
        <TextBlock Text="Embedded in different assembly" />
        <Image Source="/Module1;Component/gift.png" />
    </StackPanel>
    
    <StackPanel>
        <TextBlock Text="Embedded in different assembly in a subfolder" />
        <Image Source="/Module1;Component/Images/gift.png" />
    </StackPanel>
    
    <StackPanel>
        <TextBlock Text="Embedded in different assembly in a subfolder using full Pack URI format" />
        <Image Source="pack://application:,,,/Module1;Component/Images/gift.png" />
    </StackPanel>
    
    <StackPanel>
        <TextBlock Text="Setting imagesource from code-behind" />
        <Image x:Name="image1" />
    </StackPanel>
    

    相关代码隐藏:

    public Window1()
    {
        InitializeComponent();
    
        //Here we have to use the full Pack URI
        //image1.Source = new BitmapImage(new Uri("/Module1;Component/Images/gift.png")); //Throws exception..
        image1.Source = new BitmapImage(new Uri("pack://application:,,,/Module1;Component/Images/gift.png"));
    }
    

    更新
    当资源在使用它的同一个程序集中时,应该没有理由包含 URI 的 /NameOfDll;Component/ 部分。我不确定为什么它不适用于您的情况。

    我在 Module1 中添加了一个窗口,它仅在其自己的程序集中引用了一个图像,并且似乎工作正常。在 WPF 应用程序中单击按钮时会显示该窗口。

    <Window x:Class="Module1.WindowTest"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 mc:Ignorable="d" 
                 d:DesignHeight="300" d:DesignWidth="300"
                 Title="Window from Module1">
        <Grid>
            <Image Source="Images/gift.png" />
        </Grid>
    </Window>
    

    【讨论】:

    • 感谢您的回复!但是,在这个例子中,如果 Module1 有 Window2 而 Window2 想要显示 Module1/images/gift.png 怎么办?我就是这种情况,我认为 Module1 可以简单地使用“Images/gift.png”,但是,例如,我必须输入“/Module1;Component/Images/gift.png”。
    • 离开 pack://application:,, 确实为我节省了很多空间,感谢您的提示。我之前尝试过,但我没有意识到我必须使用 /Module(而不是 Module)来领导,这就是它不起作用的原因
    • 糟糕,请注意,我也尝试过“/Images/gift.png”(带有前面的斜杠)。如果这是生活中的事实,那么我愿意接受它,但我想我很好奇什么是“在同一个程序集中”,或者不考虑它似乎在同一个程序集中,但不起作用
    • 我认为它应该可以工作而无需编写 /Module1;Component/ - 请参阅我更新的答案。
    • 好吧,找到了我的最后一个问题,我的模块窗口在 /Views 文件夹中,所以我必须这样做
    猜你喜欢
    • 1970-01-01
    • 2013-09-21
    • 2011-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多