代码之家  ›  专栏  ›  技术社区  ›  alex2k8

使用LoadComponent加载外部XAML文件

wpf
  •  2
  • alex2k8  · 技术社区  · 15 年前

    我找到了一些 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与“build action:none”和“copy always”相同。

    <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”。

    什么是解决方案?

    4 回复  |  直到 15 年前
        1
  •  4
  •   Jim Carnicelli    15 年前

    我要用这个。我的具体目标是将ResourceDictionary加载到应用程序类中,以便从原始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”作为按钮的背景色。皮肤会立即发生变化,不需要重新加载应用程序或窗口。

        2
  •  3
  •   alex2k8    15 年前

    似乎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应该是一个相对路径。在申请:///权限下处理。

    MSDN

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

    可能的数据文件有:

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

    • 编译的资源文件 进入本地程序集。

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

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

    • 内容文件。

    • 源站文件。

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

    所以我将app.xaml转换为内容文件(详细信息如下 here )

    1. 根据内容生成操作
    2. 复制到输出目录以始终复制
    3. [程序集:assemblyAssociatedContentFile(“app.xaml”)]

    结果引发了这样的异常:“application/xaml+xml”contenttype无效。

        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”中的外部文件,因此假设任务没有解决方案。

        3
  •  0
  •   Akash Kava    15 年前

    您需要绝对文件URI,包括整个文件:://c:/etc.。因为relative只在应用程序的资源中使用。

        4
  •  0
  •   Wolfgang Grinfeld    15 年前

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

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