【问题标题】:Load external XAML file using LoadComponent使用 LoadComponent 加载外部 XAML 文件
【发布时间】:2009-04-02 15:47:25
【问题描述】:

我发现了一些evidence,这是可能的,

self.scene = Canvas()
Application.LoadComponent(self.scene, Uri('app.xaml', UriKind.Relative))

但我的代码失败了:

class Program
{
    [STAThread]
    static void Main(string[] args)
    {
        Canvas scene = new Canvas();
        Application.LoadComponent(scene, new Uri("app.xaml", UriKind.Relative));
    }
}

我正在使用具有“构建操作:无”和“始终复制”的相同 app.xaml。

<Canvas
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="System.Windows.Controls.Canvas"
    x:Name="ball_design" >

    <Canvas x:Name="workaround_canvas" >

        <TextBlock x:Name="fps" Canvas.Left="10" Canvas.Top="10" Height="40" Canvas.ZIndex="10000" Text="-- fps" />
    <Canvas x:Name="wpfe_ball_0" Width="52" Height="52" Canvas.Left="0" Canvas.Top="30">
      <!-- Layer 3/<Group>/<Path> -->
      <Path Opacity="0.900000" StrokeThickness="2.000000" Stroke="#ffa6d000" StrokeMiterLimit="1.000000" Fill="#ffcbff00" Data="F1 M 51.000000,26.000000 C 51.000000,39.806641 39.807129,51.000000 26.000000,51.000000 C 12.192871,51.000000 1.000000,39.806641 1.000000,26.000000 C 1.000000,12.193359 12.192871,1.000000 26.000000,1.000000 C 39.807129,1.000000 51.000000,12.193359 51.000000,26.000000 Z"/>

      <!-- Layer 3/<Group>/<Path> -->
      <Path Opacity="0.740000" Data="F1 M 43.143066,13.087891 C 50.602051,22.888672 49.009766,36.642578 39.590332,43.812500 C 30.170898,50.980469 16.489258,48.842773 9.032715,39.042969 C 1.573242,29.240234 3.166016,15.486328 12.584961,8.316406 C 22.003906,1.149414 35.685547,3.285156 43.143066,13.087891 Z">
        <Path.Fill>
          <RadialGradientBrush MappingMode="Absolute" GradientOrigin="156.791016,170.453125" Center="156.791016,170.453125" RadiusX="53.626404" RadiusY="53.626404">
            <RadialGradientBrush.GradientStops>
              <GradientStop Offset="0.000000" Color="#ffffffff"/>
              <GradientStop Offset="0.361685" Color="#fff5f7dd"/>
              <GradientStop Offset="0.415730" Color="#ffebf0bc"/>
              <GradientStop Offset="1.000000" Color="#ffcbff00"/>
            </RadialGradientBrush.GradientStops>
            <RadialGradientBrush.Transform>
              <MatrixTransform Matrix="1.190000,0.165000,-0.165000,-1.281300,-113.414185,241.757843" />
            </RadialGradientBrush.Transform>
          </RadialGradientBrush>
        </Path.Fill>
      </Path>

      <!-- Layer 3/<Group>/<Path> -->
      <Path Fill="#ffffffff" Data="F1 M 23.100586,9.477539 C 24.741699,11.634766 23.116211,15.630859 19.470703,18.404297 C 15.825684,21.178711 11.540039,21.678711 9.899414,19.522461 C 8.258301,17.365234 9.883789,13.369141 13.529297,10.594727 C 17.174316,7.821289 21.459961,7.321289 23.100586,9.477539 Z"/>
    </Canvas>
    <TextBlock x:Name="dbgwin" FontSize="10" Canvas.Top="10" Canvas.Left="250" Height="500" Width="200" Text="IronPython DLR" />

  </Canvas>
</Canvas>

我得到 IOException:找不到资源“app.xaml”。

什么是解决方案?

【问题讨论】:

  • 嗯...我提到的代码是SilverLight代码,所以可能是LoadComponent不能用来加载外部文件。

标签: wpf


【解决方案1】:

我得到了这个工作。我的具体目标是将 ResourceDictionary 加载到 App 类中,这样我就可以从原始 XAML 文件加载自定义皮肤。就是这样。首先,在 App.xaml 中,添加以下内容:

    protected override void OnStartup(StartupEventArgs e) {
        base.OnStartup(e);
        LoadSkin("Skins/Skin1.xaml");

    }

    private void LoadSkin(string FilePath) {
        XmlReader XmlRead = XmlReader.Create(FilePath);
        Application.Current.Resources = 
            (ResourceDictionary)XamlReader.Load(XmlRead);
        XmlRead.Close();
    }

创建一个“bin\Debug\Skins”文件夹并添加一个“Skin1.xaml”,内容如下:

<ResourceDictionary 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
    <Style x:Key="ButtonAStyle" TargetType="{x:Type Button}">
        <Setter Property="Control.Background" Value="Green" />
        <Setter Property="Control.Foreground" Value="White" />
    </Style>
</ResourceDictionary>

特定于皮肤

在这种特殊情况下,您必须确保在各个窗口中正确使用样式资源。这是一个例子:

<Button 
    Name="button1" 
    Style="{DynamicResource ButtonAStyle}" 
    Click="button1_Click"
>Button</Button>

这是一个可以尝试的巧妙技巧。在 button1_Click() 中,尝试添加与上述 App.OnStartUp() 中相同的代码,但将“Skin2.xaml”和“Red”作为按钮的背景颜色。皮肤会立即改变,无需重新加载应用或窗口。

【讨论】:

  • 1.你的VS版本是什么?我在 VS2008 中没有看到这样的构建操作“内容复制到输出”? 2. 你确定 Skin1.xaml 只是复制,而不是作为资源编译成 .exe 吗?
  • 我正在使用 VS 2008。不过,看起来我自欺欺人了。如果我将“构建操作”设置为“内容”,这对我有用。如果我只是将松散的文件放在 bin\Debug\Skins\ 中,它就不起作用。 :-P 我现在正在寻找修复方法。
  • 已修复。关键是使用 XamlReader 而不是 Application.LoadComponent()。我在这里更新了代码以反映它。
  • 不幸的是,XamlReader.Load 仅适用于其中没有事件的 xaml 文件
【解决方案2】:

LoadComponent 似乎无法加载外部 XAML 文件。

我查看了源代码:

    public static void LoadComponent(Object component, Uri resourceLocator) 
    {
        ...

        // Passed a relative Uri here.
        // needs to resolve it to Pack://Application.
        //..\..\ in the relative Uri will get stripped when creating the new Uri and resolving to the 
        //PackAppBaseUri, i.e. only relative Uri within the appbase are created here
        Uri currentUri = new Uri(BaseUriHelper.PackAppBaseUri, resourceLocator); 

        ...
    }

所以resourceLocator 应该是一个相对路径。并且会在 application:/// 权限下处理。

MSDN

WPF 支持两种权限: application:/// 和 siteoforigin:///。 application:/// 权限 标识应用程序数据文件 在编译时已知,包括 资源和内容文件。这 siteoforigin:/// 权威标识 原始文件的站点。

可能的数据文件有:

  • 封装和部件类似于 应用程序和文件,其中 应用程序(包)可以包括 一个或多个文件(部分), 包括:

  • 已编译的资源文件 进入当地议会。

  • 已编译的资源文件 到引用的程序集中。

  • 已编译的资源文件 到一个引用程序集中。

  • 内容文件。

  • 源文件的站点。

前 4 个文件可以通过 application:// 访问,但我正在寻找外部文件,所以唯一的选项是“内容文件”。

于是我把 app.xaml 变成了内容文件(详情为here

  1. 根据内容构建操作
  2. 复制到输出目录以始终复制
  3. [程序集:AssemblyAssociatedContentFile("app.xaml")]

因此引发了这样的异常:'application/xaml+xml' ContentType is not valid.

    public static void LoadComponent(Object component, Uri resourceLocator) 
    {
        ...

            if (!MimeTypeMapper.BamlMime.AreTypeAndSubTypeEqual(contentType)) 
            {
                throw new Exception(SR.Get(SRID.ContentTypeNotSupported, contentType)); 
            }
        ...
    }

所以 LoadComponent 需要 'application/baml+xml' 而不是 'application/xaml+xml'。

我不知道如何将 xaml 作为外部文件存储在 'application/baml+xml' 中,因此假设该任务没有解决方案。

【讨论】:

  • 最新研究表明,有了 BAML,我们就可以加载它。稍后会更改响应。
  • 如何获得 BAML?
【解决方案3】:

您将需要绝对文件 URI,包括整个 file://c:/ 等。因为相对仅在应用程序的资源中使用。

【讨论】:

  • 现在我得到 ArgumentException: Cannot use absolute URI.
【解决方案4】:

为了让 LoadComponent 在 XAML 资源上工作,它需要有一个“页面”的构建操作。然后,即使在控制台应用程序中,LoadComponent 也可以工作。

当想要在服务器应用程序中访问从 Blend 生成的示例数据时,这可能很有用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-10
    • 1970-01-01
    • 1970-01-01
    • 2013-12-07
    • 1970-01-01
    相关资源
    最近更新 更多