WPF类库中的程序集范围/根级别样式

时间:2008-12-31 20:59:09

标签: c# .net wpf xaml

我有一个支持WPF的C#(2008 / .NET 3.5)类库程序集(基于this article)。
我创建了几个窗口,现在正试图创建一个共同的样式为他们设定。但是,因为它是一个类库(而不是WPF应用程序),所以我没有app.xaml(及其包含的Application和相应的Application.Resources)来存储这些样式以进行全局访问。

所以:我如何创建一个顶级的样式定义集,这些样式定义将被程序集中的所有xaml文件看到,假设我没有app.xaml(见上文)?和/或是否可以工作app.xaml添加到类库中?

仅供参考,我确实尝试在ResourceDictionary.xaml文件中创建ResourceDictionary,并将其包含在“Window.Resources”块中的每个窗口中。结果是解决了按钮等的样式......但不适用于封闭的Window。我可以将Style="{StaticResource MyWindowStyle}"放在Window的开始块中,然后编译并在VS Design窗口中显示,但在实际运行时我得到一个解析异常(找不到MyWindowStyle;我猜是Visual Studio看到的该字典包含在相关行之后,但CRL更顺序地执行,因此尚未加载ResourceDictionary)。


感谢您的想法,但仍然没有...显然类库不会隐式支持generic.xaml用法。我将generic.xaml添加到我的类库项目中,并将其Build Action设置为“Resource”。它包含:

<ResourceDictionary 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Style TargetType="{x:Type Window}" x:Key="MyWindow">
        <Setter Property="Background" Value="Black"/>
    </Style>
</ResourceDictionary>

我想要使用主题的窗口xaml如下所示:

<Window x:Class="MyAssembly.ConfigureGenericButtons"
    x:ClassModifier="internal"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Style="{StaticResource MyWindow}"
    Title="ConfigureGenericButtons">
...Buttons, etc...
</Window>

虽然VS Design窗口没有显示使用MyWindow样式的窗口(即黑色背景),但它编译良好并启动。但是,当包含此类库的应用程序进行调用以导致显示此窗口时,我会收到XamlParseException:

  

找不到名为“{MyWindow}”的资源。

我也尝试省略Style参数,以查看默认情况下窗口是否会使用该样式(我尝试使用包含和不包含的generic.xaml中的x:Key)。没有错误,但generic.xaml中定义的任何内容都没有出现。

我在这里做错了什么,或者关于如何允许在窗口上使用常见自定义样式的任何其他想法(即,不必在每个Window的xaml中定义样式) - 请注意这一点不是申请表吗?

7 个答案:

答案 0 :(得分:14)

尝试添加

Style={DynamicResource MyStyle}

在这种情况下,您无法使用StaticResource。

答案 1 :(得分:13)

这听起来像是主题的工作。

  1. /themes/generic.xaml ResourceDictionary添加到您的项目中。
  2. 将以下内容添加到AssemblyInfo.cs:[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)]
  3. 利润!
  4. 您添加到通用的任何资源都将被所有控件使用。您还可以通过在themes目录中包含具有正确主题名称的ResourceDictionary文件来制作特定于配置文件的主题(Luna,Aero等)。

    这是指向更多信息的链接:Create and apply custom themes

答案 2 :(得分:3)

如果您没有app.xaml,您仍然可以将其加载到appplication级别的资源中,但是您必须编写代码(而不是xaml)来执行此操作,类似于此...

void LoadIt()
{
     ResourceDictionary MyResourceDictionary = new ResourceDictionary();
     MyResourceDictionary.Source = new Uri("MyResources.xaml", UriKind.Relative);
     App.Current.Resources.MergedDictionaries.Add(  MyResourceDictionary )
}

查看此网站以获取示例: http://ascendedguard.com/2007/08/one-of-nice-features-about-wpf-is-how.html

答案 3 :(得分:1)

博士。 WPF(或以前称为WPF博士的人)在这个问题上有一个很棒的post

这里是他们创建Application对象并添加资源的帖子的摘录:

if (Application.Current == null)
{
    // create the Application object
    new Application();

    // merge in your application resources
    Application.Current.Resources.MergedDictionaries.Add(
        Application.LoadComponent(
            new Uri("MyLibrary;component/Resources/MyResourceDictionary.xaml",
            UriKind.Relative)) as ResourceDictionary);
}

由于我的程序集是通过interop托管的,我必须添加设置ShutdownMode,如下所示并在完成时关闭:

new Application() { ShutdownMode = ShutdownMode.OnExplicitShutdown };

它就像一个魅力。

答案 4 :(得分:0)

如果在Window.Resource中加载它,则该字典仅适用于该窗口的子项。您需要为窗口及其子项提供它。

尝试在app.xaml文件中加载它。这应该使它成为应用程序级资源,而不是窗口级资源。

答案 5 :(得分:0)

所以在花了很多时间之后我终于弄明白了。以下是:

  1. 在WPF控件库中,添加名为themes
  2. 的新文件夹
  3. themes文件夹中,添加名为generic.xaml
  4. 的资源字典
  5. generic.xaml内,使用以下语法添加资源:

    <SolidColorBrush x:Key="{ComponentResourceKey {x:Type local:UserControl1}, MyEllipseBrush}" Color="Blue" />
    
  6. 在您的控件中,使用以下语法访问此资源:

    Background="{StaticResource {ComponentResourceKey {x:Type local:UserControl1}, MyEllipseBrush}}"
    
  7. 注意事项:

    1. 当您创建新的WPF控件库时,Visual Studio通常会自动为您完成第1步和第2步。
    2. 我不完全理解ComponentResourceKey的第一个参数的用途,但它是必需的。使用将使用此资源的控件的名称。
    3. Visual Studio的设计人员无法在我的案例中找到资源。这可能是一个缓存问题,我不确定。但在运行时它可以很好地工作。
    4. 您可以在this MSDN article
    5. 中阅读有关此语法的更多详细信息

      希望这会让生活更轻松。

答案 6 :(得分:0)

这是在 .NET类库共享资源“模块范围”的简单解决方案。重要的是,它似乎在 Visual Studio 中牢固地保留了 XAML设计器显示功能和行为。

首先添加一个新的从ResourceDictionary派生的 C#类,如下所示。该类的实例将替换需要查看共享资源的类库中每个ResourceDictionary(或其他带有System.Windows.Control的组件)上的默认ResourceDictionary

ComponentResources.cs:

using System;
using System.Reflection;
using System.Windows;
using System.Windows.Markup;

namespace MyNamespace
{
    [UsableDuringInitialization(true), Ambient, DefaultMember("Item")]
    public class ComponentResources : ResourceDictionary
    {
        static ResourceDictionary _inst;

        public ComponentResources()
        {
            if (_inst == null)
            {
                var uri = new Uri("/my-class-lib;component/resources.xaml", UriKind.Relative);
                _inst = (ResourceDictionary)Application.LoadComponent(uri);
            }
            base.MergedDictionaries.Add(_inst);
        }
    };
}

请确保分别使用名称空间和程序集文件名(而不是“ \”替换上一个代码段中的 MyNamespace my-class-lib )。 .dll'扩展名)来自您自己的项目:

将新的ResourceDictionary XAML 文件添加到您的类库项目中。与“应用程序”程序集不同,Visual Studio UI中没有此选项,因此您必须手动进行操作。这将包含您要在整个类库中共享的资源:

$(ProjectDirectory)\ Resources.xaml:

<ResourceDictionary xmlns="http://schemas.microsoft.com/netfx/2009/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:MyNamespace">

    <!-- define the resources to be shared across the whole class library here -->

    <!-- example for demonstration -->
    <Style TargetType="Rectangle">
        <Setter Property="Fill" Value="Red" />
    </Style>

<ResourceDictionary>

Build Action (构建操作)设置为“页面” ,并确保“文件属性”信息如下所示:

enter image description here

最后,转到项目中需要引用共享资源的 XAML 文件,并替换默认的ResouceDictionary(通常是在Resources属性上XAML根元素)和一个ComponentResources实例。这将保存每个组件的私有资源,如您在上面的代码中所见,构造函数将模块范围的共享单例ResourceDictionary附加为“合并字典”。对应该看到共享资源的每个控件执行此操作,即使那些没有自己私有资源的控件也是如此。当然,您也可以跳过此步骤以根据需要排除某些控件。例如:

<UserControl x:Class="MyNamespace.UserControl1"
             xmlns="http://schemas.microsoft.com/netfx/2009/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:MyNamespace">

    <UserControl.Resources>
        <local:ComponentResources>
            <!-- Keep any existing non-shared resources here from before -->
            <!-- Can be empty if this control has no private resources -->
        </local:ComponentResources>
    </UserControl.Resources>

    <!-- to demonstrate that the Style in the above example is effective... -->
    <Grid>
        <Rectangle Width="10" Height="10" />
    </Grid>

</UserControl>

如广告所示,它很好用,包括在 XAML设计器 ...

enter image description here