【问题标题】:Sharing WPF-Dictionary from another assembly从另一个程序集共享 WPF 字典
【发布时间】:2016-03-18 14:00:43
【问题描述】:

好的,我已经为此绞尽脑汁了几个小时,但仍然找不到解决方案。

首先我将解释我创建的简单测试用例: 解决方案

- ClassLibrary1
  - Dictionary1.xaml
- WpfApplication3
  - App.config
  - App.xaml
  - Dictionary2.xaml
  - MainWindows.xaml

类库1:

该项目具有允许我添加 wpf-dictionary 所需的参考:
PresentationCore、PresentationFramework、Systam.Xaml、windowsbase
(以及任何常规类库的所有标准程序集)

这是Dictionary1.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Color x:Key="PrimaryBackgroundColor">#FF030010</Color>
    <SolidColorBrush x:Key="PrimaryBackgroundBrush" Color="{StaticResource PrimaryBackgroundColor}" />
</ResourceDictionary>

WpfApplication3:

这个项目只是在 wpf-form 上显示一个按钮。

Dictionary2.xaml:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:WpfApplication3">
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="pack://application:,,,/ClassLibrary1.dll;component/Dictionary1.xaml"/>
    </ResourceDictionary.MergedDictionaries>
    <Style TargetType="Button">
        <Setter Property="Background" Value="{StaticResource PrimaryBackgroundBrush}" />
    </Style>
</ResourceDictionary>

MainWindow.xaml:

<Window x:Class="WpfApplication3.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication3"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Dictionary2.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>
    <Grid>
        <Button Content="aaa" Width="100" Height="40" />
    </Grid>
</Window>

就是这样 - 如您所见,非常简单。
这里唯一的事情是dictionary2需要使用dictionary1中的资源。

因此有两种方法可以引用另一个程序集:

选项 1: 类库是您的解决方案中的一个项目,您的 WpfApplication 添加对同一解决方案中的类库项目的引用。这是通过 Add-Reference/Projects 完成的,在这种情况下一切都很好。

选项 2: 类库不是您的解决方案。 (实际上可以像我的例子一样) 但是,您可以通过添加对 ClassLibrary1.Dll 的引用来添加引用,该引用位于您的 bin\debugbin\release 文件夹。 在那种情况下,通往地狱的门户就打开了。 Dictionary2 抱怨它找不到资源“PrimaryBackgroungBrush”,并且在执行时它会粉碎 抱怨找不到dictionary1.xaml

抛出异常:PresentationFramework.dll 中的“System.Windows.Markup.XamlParseException” 和内部异常: {“无法加载文件或程序集 'ClassLibrary1.dll, Culture=neutral' 或其依赖项之一。 系统找不到指定的文件。":"ClassLibrary1.dll, Culture=neutral"}

问题是使用 option2 是必不可少的,因为我想在其他 wpf 项目之间共享同一个字典,而无需 将 ClassLibrary1 项目作为其解决方案的一部分。

建议的重现方式:

  1. 在 Visual Studio 中为 WPF 应用程序创建一个新的解决方案。
  2. 将类库项目添加到解决方案中。
  3. 在类库项目中,添加对以下程序集的引用:PresentationCore、PresentationFramework、Systam.Xaml、windowsbase
  4. 将 Wpf-Dictionary 'Dictionary1' 添加到您的类库项目并复制代码。 (您可以从 wpf 项目中复制一个,因为它不会作为选项存在于类库的添加项中)
  5. 将 Wpf-Dictionary 'Dictionary2' 添加到您的 wpf 应用程序并复制代码。
  6. 复制 MainWindow 的代码。

现在:

  1. 添加对类库的引用(作为项目,从添加引用对话框中的项目选项卡) 构建一切 - 一切都应该工作。

  2. 删除对类库的引用。
    添加对类库的引用(作为 dll,从浏览选项卡并在您的 classlibrary/bin/debug 或 release 文件夹中找到它) 构建一切 - 你会注意到我的问题。

这个问题有什么解决办法吗?

更新 1

我将 dictionary2.xaml 中的行从:
&lt;ResourceDictionary Source="pack://application:,,,/ClassLibrary1.dll;component/Dictionary1.xaml"/&gt;
至:
&lt;ResourceDictionary Source="pack://application:,,,/ClassLibrary1;component/Dictionary1.xaml"/&gt;

现在项目编译和执行没有错误,但是在设计时 - dictionary2 的 xaml 视图表明它找不到资源:'PrimaryBackgroundBrush`,并在其下方加上丑陋的卷曲下划线。
所以这是一个进步——但我仍然对此不满意。
任何想法如何解决这个问题?

更新 2 如前所述 - 现在一切都编译并执行。
但是,您在下图中看到的内容让我很生气,
我只是想确保将类库添加为 .Dll 文件而不是项目的其他人 100% 确保他们没有遇到图片中可以看到的问题,这意味着他们的 xaml 智能感知可以在设计时识别资源.

【问题讨论】:

  • 我无法重现该问题。你忘了提到WindowsBase(作为类库项目的参考)。然后类库“添加项目”对话框中没有 Wpf-Dictionary(对于 wpf 应用程序,它称为Resource Dictionary (WPF)),可以通过从 wpf 应用程序复制一个来解决。然后一切编译。从解决方案中删除类库并引用 dll - 仍然有效。
  • @Sinatr 你确定你添加了我在 wpf 项目中展示的第二本字典吗? (也感谢我将您指出的信息添加到问题正文中)
  • 我也尝试过重现您的问题,但没有成功。程序项目中声明的字典合并了DLL的字典,DLL字典中的资源可以在程序项目的字典中被引用,而该字典又可以成功地合并到Window的字典中。依赖于资源的渲染元素正确显示。请仔细检查所有内容(包括字典文件的构建设置),简化您的示例,并确保您包含了一个好的minimal reproducible example
  • 好的,上次更新 - 只是为了 100% 确定 - 您说在将其添加为 .dll(不是项目)后,您看不到我在设计时显示的错误。
  • 思考..也许它是一个更清晰的东西?

标签: c# .net wpf xaml resourcedictionary


【解决方案1】:

我可以想象有关该 dll 的文档会是什么样子:

  • 在项目中引用dll

  • 将此添加到项目中的资源字典中:

<ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="pack://application:,,,/ClassLibrary1.dll;component/Dictionary1.xaml"/>
</ResourceDictionary.MergedDictionaries>
  • 将此添加到每个窗口/用户控件:

<Window.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="Dictionary2.xaml"/>
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Window.Resources>

看起来很糟糕。

如何在你的库中创建每个窗口/用户控件必须引用的管理器,它会自动执行操作?


这是我在 cmets 中提到的主题管理器的剪辑(它确实会自动合并),考虑一下易用性。

xaml(将其添加到必须在设计/运行时支持主题切换的每个窗口/用户控件):

         local:Theme.Theme=""

cs(这部分必须是库的一部分):

public static class Theme
{
    public static readonly DependencyProperty ThemeProperty =
        DependencyProperty.RegisterAttached("Theme", typeof(string), typeof(Theme), new PropertyMetadata(null, (d, e) =>
        {
            var theme = (string)e.NewValue;
            // in run-time set theme to specified during init
            if (!DesignerProperties.GetIsInDesignMode(d))
                theme = _theme;
            var element = d as FrameworkElement;
            element.Resources.MergedDictionaries.Clear();
            if (!string.IsNullOrEmpty(theme))
            {
                var uri = new Uri($"/MyPorject;component/Themes/{theme}.xaml", UriKind.Relative);
                element.Resources.MergedDictionaries.Add(new ResourceDictionary() { Source = uri });
            }
        }));
    public static string GetTheme(DependencyObject obj) => (string)obj.GetValue(ThemeProperty);
    public static void SetTheme(DependencyObject obj, string value) => obj.SetValue(ThemeProperty, value);

    static string _theme = "Generic";

    static string[] _themes = new[]
    {
        "Test",
    };

    /// <summary>
    /// Init themes
    /// </summary>
    /// <param name="theme">Theme to use</param>
    public static void Init(string theme)
    {
        if (_themes.Contains(theme))
            _theme = theme;
    }
}

P.S.:功能是原始的(在我的情况下就足够了),但应该给你一个想法。

【讨论】:

  • 首先,谢谢您的回答。我将尽可能深入地研究它,看看这个建议如何帮助解决这个问题。其次,假设不正确-我不会在每个window/usercontrol资源中放入一个合并字典-相反-我会将它放入app.xaml中-我想知道这是否意味着它仍然会在每个实例中复制字典-我认为它没有这样做..现在+1 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-17
  • 2013-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多