从另一个程序集中共享 WPF-Dictionary [英] Sharing WPF-Dictionary from another assembly

查看:58
本文介绍了从另一个程序集中共享 WPF-Dictionary的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好的,我已经为此纠结了几个小时,但仍然找不到解决方案.

Ok, I busting my head on this for few hours now and still cannot find a solution.

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

first I shall explain the simple test case I created: Solution

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

ClassLibrary1:

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

That project has the required references to allow me to add wpf-dictionary:
PresentationCore, PresentationFramework, Systam.Xaml, windowsbase
(Along with all standard assemblies for any regular class library)

这是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 表单上显示一个按钮.

This project just display a button on a 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 中的资源.

That's all - very simple as you can see.
The only thing here is that dictionary2 need to use resource from dictionary1.

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

And so there are two ways to reference another assembly:

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

Option 1: The class-library is a project in your solution and your WpfApplication adds reference to the class library project which is in the same solution. this is done via Add-Reference/Projects, And in that situation all works great.

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

Option 2: The class-library is not your solution. (actually it can be like in my example) however you add reference by adding reference to ClassLibrary1.Dll which resides either in your bin\debug or bin\release folders. In that situation a portal to hell is opened. Dictionary2 complains it cannot find the resource 'PrimaryBackgroungBrush' and upon execution it crush complaining it cannot find the dictionary1.xaml

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

Exception thrown: 'System.Windows.Markup.XamlParseException' in PresentationFramework.dll and the inner exception: {"Could not load file or assembly 'ClassLibrary1.dll, Culture=neutral' or one of its dependencies. The system cannot find the file specified.":"ClassLibrary1.dll, Culture=neutral"}

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

The problem is that using option2 is essential as I want to share the same dictionary among other wpf projects without having the ClassLibrary1 project as part of their solution.

建议的重现方式:

Suggested way to reproduce:

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

现在:

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

  1. Add reference to class library (as project, from projects tab in add refernce dialog) Build everything - all should work.

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

Remove the refernce to class library.
Add reference to class library (as dll, from browse tab and find it in your classlibrary/bin/debug or release folder) Build everything - you will notice my problem.

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

Any solution to this problem?

更新 1

我将 dictionary2.xaml 中的行从:
<ResourceDictionary Source="pack://application:,,,/ClassLibrary1.dll;component/Dictionary1.xaml"/>
致:
<ResourceDictionary Source="pack://application:,,,/ClassLibrary1;component/Dictionary1.xaml"/>

I changed the line in dictionary2.xaml from:
<ResourceDictionary Source="pack://application:,,,/ClassLibrary1.dll;component/Dictionary1.xaml"/>
To:
<ResourceDictionary Source="pack://application:,,,/ClassLibrary1;component/Dictionary1.xaml"/>

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

And now the project compiles and execute without an error, However while in design time - the xaml view of dictionary2 indicate that it cannot find the resource: 'PrimaryBackgroundBrush` and puts the ugly curly underline below it.
So its a progress - but i'm still not happy with that.
Any ideas how to solve that?

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

UPDATE 2 As previously stated - everything compiles and execute now.
However what you see in the following picture annoys me,
I just want to be sure that others who added the class library as .Dll file and not as project 100% sure they don't get that problem which can be seen in the picture, meaning their xaml intellisense can recognize the resource during design time.

推荐答案

我可以想象关于那个 dll 的文档会是什么样子:

I could imagine how documentation about that dll will looks like:

项目中引用dll

reference dll in the project

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

    add this to resource dictionary in the project:

  • <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="pack://application:,,,/ClassLibrary1.dll;component/Dictionary1.xaml"/>
    </ResourceDictionary.MergedDictionaries>
    

    • 将此添加到每个窗口/用户控件:

      add this to each window/usercontrol:

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

      看起来很糟糕.

      如何在您的库中设置管理器,每个窗口/用户控件都必须引用它并自动执行操作?

      How about making manager in your library which has to be referenced by each window/usercontrol and it will do things automatically?

      这是我在评论中提到的主题管理器的剪辑(它会自动合并),考虑易用性.

      Here is a cut from theme manager I mentioned in comments (it does merging automatically), think about easy of use.

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

      xaml (add this to each window/usercontrol which has to support theme switching in design/run time):

               local:Theme.Theme=""
      

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

      cs (this part has to be a part of library):

      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.:功能很原始(对我来说已经足够了),但应该给你一个想法.

      P.S.: functionality is primitive (it is sufficient in my case), but should give you an idea.

      这篇关于从另一个程序集中共享 WPF-Dictionary的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆