在WPF用户控件库中,最简单的共享UserControl之间资源的方法是什么?

13

有一个 WPF 用户控件库,其中包含两个(或更多)用户控件。我需要在这些用户控件中使用相同的样式。如何共享此样式? 例如:

这是样式:

<Style x:Key="customLabelStyle" TargetType="Label">
    ...
</Style>

用户控件 A:

<UserControl x:Class="Edu.Wpf.Example.UserControlA"
   ...xmlns stuff... >
   <Grid>
      ... some xaml markup...
      <Label Style="{StaticResource customLabelStyle}"/>
   </Grid>
</UserControl>

用户控件 B:

 <UserControl x:Class="Edu.Wpf.Example.UserControlB"
   ...xmlns stuff... >
   <Grid>
      ... some another xaml markup...
      <Label Style="{StaticResource customLabelStyle}"/>
   </Grid>
</UserControl>

那么我该如何在库中的用户控件之间共享此样式,而不涉及应用程序app.xaml资源字典呢?

更新

我可以将Themes\Generic.xaml添加到我的库中并在那里定义样式。但在这种情况下,我必须使用ComponentResourceKey作为样式的键。对吗?它很长,而且表达不太方便...

3个回答

14

假设你有一个定义颜色的资源,如下所示:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Color A="#FF" R="#FF" G="#22" B="#11" x:Key="MyRed"/>
    <Color A="#FF" R="#00" G="#FF" B="#21" x:Key="MyGreen"/>
    <Color A="#FF" R="#00" G="#22" B="#FF" x:Key="MyBlue" />


    <SolidColorBrush x:Key="MyGreenBrush" Color="{StaticResource MyGreen}"/>
    <SolidColorBrush x:Key="MyRedBrush" Color="{StaticResource MyRed}"/>
    <SolidColorBrush x:Key="MyBlueBrush" Color="{StaticResource MyBlue}"/>
</ResourceDictionary>

还有另一个定义基本样式的方式,例如:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Style TargetType="{x:Type TextBlock}" x:Key="PocTextBlock">
        <Setter Property="FontSize" Value="16"/>
    </Style>

    <Style TargetType="{x:Type TextBox}" x:Key="MyTextBox">
        <Setter Property="FontSize" Value="20"/>
        <Setter Property="Foreground" Value="{DynamicResource MyGreenBrush}"/>
    </Style>

    <Style TargetType="{x:Type TextBlock}" x:Key="MyResultTextBlock">
        <Setter Property="FontSize" Value="16"/>
        <Setter Property="FontWeight" Value="Bold"/>
        <Setter Property="Foreground" Value="{DynamicResource MyGreenBrush}"/>
    </Style>

    <Style TargetType="{x:Type Border}" x:Key="MyBorder">
        <Setter Property="BorderBrush" Value="{DynamicResource MyGreenBrush}"/>
        <Setter Property="BorderThickness" Value="4"/>
        <Setter Property="CornerRadius" Value="5"/>
    </Style>
</ResourceDictionary>

您可以按照此处所示的方式将资源添加到App.xaml的Application.Resources标记中:

<Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="OtherStyles.xaml"/>
                <ResourceDictionary Source="Colors.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

然后,在您的所有用户控件中,您可以像示例代码所示一样使用样式或画笔作为StaticResources。


8
这是一个插件库,因此我无法使用App.xaml。 - sedovav
4
在 App.xaml 中添加 ResourceDictionary 时,可以使用以下约定方法链接其他模块: <ResourceDictionary Source="pack://application:,,,/<YourModule>;component/<YourFolder>/Colors.xaml"/>,请将 <YourModule> 和 <YourFolder> 替换为实际的模块和文件夹名称。 - Espen Medbø
3
只要它是插件库,我就无法在主应用程序中使用链接指向它。 - sedovav

2

你可以在单独的ResourceDictionary中定义共享资源,然后使用MergedDictionaries将它们合并到你的UserControl的资源中。


1
我找到了一个解决方案,它在设计时也能工作(至少在VS2010中):
public static class Resource
{
    private static readonly Dictionary<Uri, ResourceDictionary> SharedDictinaries = new Dictionary<Uri, ResourceDictionary>();

    private static void onMergedDictionaryChanged(DependencyObject source, DependencyPropertyChangedEventArgs args)
    {
        FrameworkElement el = source as FrameworkElement;
        if (el == null)
            return;

        Uri resourceLocator = new Uri(GetMergedDictionary(source), UriKind.Relative);
        ResourceDictionary dictionary;
        if (SharedDictinaries.ContainsKey(resourceLocator))
            dictionary = SharedDictinaries[resourceLocator];
        else
        {
            dictionary = (ResourceDictionary)Application.LoadComponent(resourceLocator);
            SharedDictinaries.Add(resourceLocator, dictionary);
        }

        el.Resources.MergedDictionaries.Add(dictionary);
    }

    public static readonly DependencyProperty MergedDictionaryProperty =
        DependencyProperty.RegisterAttached("MergedDictionary", typeof (String), typeof (Resource), new FrameworkPropertyMetadata(null, onMergedDictionaryChanged));

    [AttachedPropertyBrowsableForType(typeof(FrameworkElement))]
    public static String GetMergedDictionary(DependencyObject source)
    {
        return (String) source.GetValue(MergedDictionaryProperty);
    }

    public static void SetMergedDictionary(DependencyObject source, String value)
    {
        source.SetValue(MergedDictionaryProperty, value);
    }
}

这个附加属性可以应用于 FrameworkElement。假设 customLabelStyle 在 Edu.Wpf.Example 项目的 Styles.xaml 字典中定义。因此,可以通过以下方式应用此样式:
<UserControl x:Class="Edu.Wpf.Example.UserControlA"
     ...
     xmlns:res="clr-namespace:Edu.Wpf.Example.Resources"
     res:Resource.MergedDictionary="/Edu.Wpf.Example;component/Resources/Styles.xaml">
     ...
     <Label Style="{StaticResource customLabelStyle}"/>
</UserControl>

2
最后我没有费心处理所有这些附加的内容,只是直接将uri添加到样式资源字典(“pack”语法)中,放在UserControl.Resources中的两个用户控件中。这样处理更好由ReSharper来完成。 - sedovav

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接