是否有任何方法可以在WPF控件库中使用StaticResource并能够在设计时查看

本文关键字:StaticResource 方法 任何 WPF 是否 控件 | 更新日期: 2023-09-27 18:30:07

我有一个正在添加到windows窗体应用程序中的WPF控件库。我们希望允许控件本地化,但我不确定如何在不复制代码的情况下完全实现这一点。这就是我现在正在做的事情。

基本上,在windows表单应用程序中,在主应用程序启动之前,我正在实例化一个位于表单应用程序内的app.xaml(包含指向我的资源的链接,这些资源也位于表单应用中)。这非常适合运行时。

然而,我的用户控件都有Content="{StaticResource SomeVariableName}",它们最终都是空白的。我可以通过在我的控制库中有一个app.xaml和适当的资源字典来解决这个问题,这些字典与我的windows窗体应用程序中的字典相匹配。但是,这是重复的代码。

我已经尝试过但没有成功的事情:

  • 从我的表单应用程序中实例化用户控件库中的App.xaml。这不起作用,因为我的资源的URI正在寻找嵌入的资源,而不是我的本地资源字典(然后我可以在构建时简单地将资源文件从控件复制到表单应用程序中的适当位置)。我可以在这里利用DeferrableContent吗?不过,我在网上找不到太多关于这个属性以及应该如何使用它的信息
  • 我想对应用程序和字典都使用后期构建,然而,据我所知,应用程序实例化是对编译后的App.xaml的静态引用。因此,App.xaml必须至少存在于表单中
    • 我确实尝试过使用一个复制的App.xaml,并在构建后移动resourcedictionary.xaml。我认为复制的App.xsaml是可以的,因为这是驱动力,你可能无论如何都不想依赖控件中的一个(这让你想知道是否应该在控件中包含App.xaml?除非你想允许使用嵌入资源的默认值……)这也失败了,因为它无法找到资源,即使它被放置在URI应该指向的位置。反编译的代码指向Uri resourceLocater = new Uri("/WindowsFormsApplication3;component/app.xaml", UriKind.Relative);

那么,有没有什么方法可以让它发挥作用,并在设计时查看组件默认值,避免重复?或者,在这种情况下,重复可以吗?如果我的第二个项目符号的子项看起来不错(复制了App.xaml和构建复制的资源字典),我该如何使它不查找组件级项目,而是查找文件级项目?

我刚刚注意到的最后一个问题(如果需要,我可以单独发布)。我的App.xaml正在构建到代码中,所以无论如何,这都不允许我动态创建新的ResourceDictionary。有办法做到这一点吗?

最终选项。。。可能是最好的一个-无论如何,我都计划使用Andre van Heerwaarde的代码,所以我应该检查是否存在一个文件,并将其作为合并资源添加吗?基本上,在我的用户控件中有一个App.xaml,它链接到默认的嵌入式ResourceDictionary。然后,让代码动态地查找适当的本地化资源,这些资源可以是相对文件路径?我在这里看到的唯一缺点是,默认值不能随时更改。。。我甚至可能在特定的地方(使用某种约定)拥有这种外观,并且比内置的更喜欢这种外观?

哦,我不想要嵌入式资源的原因是,最终用户可以在部署构建后添加/修改新的本地化资源。

我可以添加代码,如果它能帮助你更好地可视化这一点,请告诉我。

更新

我现在遇到了另一个样式问题,而不仅仅是本地化问题。

以下是其中一个控件上的内部按钮示例:

<Button Style="{StaticResource GrayButton}"

我尝试/思考了更多的事情:

  • 我无法在ResourceDictionary设置为库项目中不允许使用ApplicationDefinitions的情况下创建app.xaml(永远不会使用)。我可以将其嵌入控件的资源中,但这总是优先于任何应用程序级别的资源,并且我失去了可定制性

这里有一个连接案例,听起来确实像我正在寻找的,但它并没有为这个提供任何真正的解决方案

我能想到的可能有效(尚未尝试)的解决方案(超出顶部……不起作用)似乎也有很多工作要做,我认为应该很简单。但是,我可以在控件中创建一些可以绑定到的依赖属性,然后允许将使用该控件的项目覆盖这些依赖属性。正如我所说,对于一个非常简单的请求来说,这似乎需要做很多工作:)。这行得通吗?更重要的是,我缺少一个更好、更简单的解决方案吗?

是否有任何方法可以在WPF控件库中使用StaticResource并能够在设计时查看

我曾经遇到过这个问题,我通过删除整个"资源是按规范字典中的键索引的对象"来解决它。

我的意思是,在一个项目中定义一个资源,并通过它的"密钥"在另一个项目中将其引用,这一简单的事实应该会让任何理智的人起鸡皮疙瘩。我想要strong参考资料。

我对这个问题的解决方案是创建一个自定义工具,将我的资源xaml文件转换为静态类,每个资源都有一个属性:

所以MyResources.xaml:

<ResourceDictionary>
  <SolidColorBrush x:Key="LightBrush" ... />
  <SolidColorBrush x:Key="DarkBrush" ... />
</ResourceDictionary>

成为MyResources.xaml.cs

public static class MyResources {
  static MyResources() {
    // load the xaml file and assign values to static properties
  }
  public static SolidColorBrush LightBrush { get; set; }
  public static SolidColorBrush DarkBrush { get; set; }
}

对于引用资源,可以使用x:Static而不是StaticResource:

<Border 
   Fill="{x:Static MyResources.LightBrush}"
   BorderBrush="{x:Static MyResources.DarkBrush}"
   ... />

现在您获得了强引用、自动完成和资源的编译时检查。

我在处理样式主题和可用的静态资源时也遇到了问题。所以,我创建了一个独立的库,基本上除了要使用的主题之外什么都没有,就像你之前链接问题的合并资源一样。

然后,在Windows表单(.xaml)中,我只是引用了该库,类似于

<Window x:Class="MyAppNamespace.MyView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" ... />
  <Window.Resources>
    <ResourceDictionary>
      <ResourceDictionary.MergedDictionaries>
        <!-- Common base theme -->
        <ResourceDictionary   Source="pack://application:,,,/MyLibrary;component/Themes/MyMainThemeWrapper.xaml" />
        </ResourceDictionary.MergedDictionaries>
      </ResourceDictionary>
  </Window.Resources>
  <Rest of XAML for the WPF window>
</Window>

"组件"似乎是指给定的"MyLibrary"项目的根。在实际的项目中,我创建了一个名为"主题"的子文件夹,因此源代码包括;组件/主题/。。。

"MyMainThemeWrapper.xaml"非常像嵌套的Merged Resource字典,它可以完美地查看其他库中的所有内容。

这是我对您的问题的部分解决方案。我没有尝试处理松散的资源,但在WinForms和WPF之间共享资源方面取得了一些成功。

  • 创建一个类库,将您的资源包含在.ResX文件中(例如resources.ResX、resources.fr.ResX等)
  • 在WPF用户控件库中创建WPF控件
  • 创建WinForms主机
  • 使用Inflution.Localization.WPF标记扩展和区域性管理器(例如)从WPF参考资源库中的资源

    <TextBlock Text="{Resx ResxName=ResourceLib.Resources, Key=Test}"/>
    
  • 将您的WPF用户控件的内容作为控件模板放入一个或多个资源字典中,例如

    <ControlTemplate x:Key="TestTemplate">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <TextBlock Text="{Resx ResxName=ResourceLib.Resources, Key=Test}"/>
        </Grid>
    </ControlTemplate>
    
  • 在用户控制中使用资源模板

    <UserControl x:Class="WpfControls.UserControl1"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" 
                 d:DesignHeight="300" d:DesignWidth="300" >
        <UserControl.Resources>
            <ResourceDictionary>
                <ResourceDictionary.MergedDictionaries>
                    <ResourceDictionary Source="ResourceDictionary.xaml"/>
                </ResourceDictionary.MergedDictionaries>
            </ResourceDictionary>
        </UserControl.Resources>
        <ContentControl Template="{StaticResource TestTemplate}" />
    </UserControl>
    
  • 添加几行代码使事情正常运行

    public partial class UserControl1 : UserControl
    {
        // we require a reference to the resource library to ensure it's loaded into memory
        private Class1 _class1 = new Class1();
        public UserControl1()
        {
            // Use the CultureManager to switch to the current culture
            CultureManager.UICulture = Thread.CurrentThread.CurrentCulture;
            InitializeComponent();
        }
    }
    

下面是一个名为WindowsFormsHost.7z 的简单演示应用程序