1

具有以下非常简单的 xaml:

<DocumentViewer Name="dv">
    <FixedDocument Name="fd" Loaded="fd_loaded">
        <FixedDocument.Resources>
            <Style x:Key="TestStyle">
                <Style.Setters>
                    <Setter Property="TextBlock.Foreground" Value="BlueViolet"/>
                </Style.Setters>
            </Style>
            <SolidColorBrush x:Key="foregroundBrush" Color="Orange"/>
        </FixedDocument.Resources>
        <PageContent Name="pc">
            <FixedPage Name="fp" Width="800" Height="600" Name="fp">
                <TextBlock Name="tb" Style="{DynamicResource TestStyle}">
                        Lorem ipsum
                </TextBlock>
                <TextBlock Foreground="{DynamicResource foregroundBrush}" Margin="20">
                        Lorem ipsum
                </TextBlock>
            </FixedPage>
        </PageContent>
    </FixedDocument>
</DocumentViewer>

在这里使用动态资源(我在更复杂的情况下实际上需要)不起作用。使用静态资源将 TextBlocks 着色为所需的颜色。将资源移动到 FixedPage 的级别也可以解决问题。但我想在顶级元素上有一个通用资源字典(因为用户可以对颜色、字体等进行运行时更改)。将资源放在应用程序级别也确实有效。但这不是一个很好的选择。

任何人都知道为什么这不起作用。它与 TextBlock 向上的逻辑树有关吗?

MSDN 资源概述指出:

查找过程在设置属性的元素定义的资源字典中检查请求的键。

  • 如果元素定义了 Style 属性,则检查 Style 中的 Resources 字典。
  • 如果元素定义了 Template 属性,则检查 FrameworkTemplate 中的 Resources 字典。

查找过程然后向上遍历逻辑树,到达父元素及其资源字典。这一直持续到到达根元素。

根据上述MSDN的解释,我还尝试将Brush和Style放入(虚拟)样式的资源中。但这也没有用。

真的有感觉,这不可能那么复杂,但很可能是我监督的东西。任何帮助表示赞赏。

编辑

将 TextBlock 命名为“tb”然后使用 tb.FindResource("TestStyle") 会引发异常。因此,显然无法找到该资源。如果我检查 LogicalTreeHelper.GetParent(tb) 并为找到的父母重复该操作,我会得到预期的结果: TextBlock > FixedPage > PageContent > FixedDocument ...

编辑2

这很完美。与之前预测的 XAML 有什么区别?

<Window x:Class="WpfDynamicStyles2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.Resources>
            <SolidColorBrush x:Key="resBrush" Color="Orange"></SolidColorBrush>
        </Grid.Resources>
            <StackPanel>
            <Button>
                <TextBlock Foreground="{DynamicResource resBrush}">Dummy text...</TextBlock>
            </Button>           
        </StackPanel>
    </Grid>
</Window>

编辑3

private void fd_Loaded(object sender, RoutedEventArgs e)
{
    Object obj = pc.TryFindResource("foregroundBrush");
    obj = fp.TryFindResource("foregroundBrush");
    obj = tb.TryFindResource("foregroundBrush");
}

无法解析放置在文本框的 Foreground 属性上的动态资源(实际资源位于 FixedDocument.Resources 级别)。同样在代码后面使用 TryFindResource 来自 pc (PageContent) 但来自 fp (FixedPage) 和 tb (TextBlock) 它无法解析资源(obj 为空)。在 XAML 标记中使用静态资源时,一切正常。

4

2 回答 2

0

走好风格是一个很好的设计,但不是必需的。要制作基于动态颜色的同名(键控)画笔,我们可以使用动态颜色字典(不是画笔字典)

解决方案可以如下...

  1. 创建单个画笔资源字典。
  2. DynamicResource用属性引用画笔中的颜色。
  3. 在每个字典中创建具有相同键控颜色资源的多个资源字典。
  4. 根据用户要求,清除并添加到Application.Current.resources.MergedDictionaries.

例子

  1. 使用具有以下 XAML 的窗口创建一个 WPF 项目......

     <Window.Resources>
       <ResourceDictionary>
         <ResourceDictionary.MergedDictionaries>                
            <ResourceDictionary Source="Resources/Window11Resources.xaml"/>
         </ResourceDictionary.MergedDictionaries>
       </ResourceDictionary>
     </Window.Resources>
     <DockPanel LastChildFill="True">
       <ComboBox DockPanel.Dock="Top" VerticalAlignment="Top"
              SelectionChanged="ComboBox_SelectionChanged"
              SelectedIndex="0">
        <ComboBox.ItemsSource>
            <Collections:ArrayList>
                <System:String>Orange</System:String>
                <System:String>Red</System:String>
                <System:String>Blue</System:String>
            </Collections:ArrayList>
        </ComboBox.ItemsSource>
    </ComboBox>
    
    <DocumentViewer>
        <FixedDocument>
            <PageContent>
                <FixedPage Width="793.76" Height="1122.56">
                    <TextBlock
                          FontSize="30"
                          Foreground="{StaticResource LabelColorBrush}"
                          Text="Test"/>
                </FixedPage>
            </PageContent>                
        </FixedDocument>
    </DocumentViewer>        
    

如果您观察到窗口不需要使用任何动态的东西。所有引用都可以保持静态。所以LabelColorBrush可以查字典Window11Resources.xaml

  1. Window11Resources.xaml字典中添加动态颜色画笔。

     <SolidColorBrush x:Key="LabelColorBrush"
                  Color="{DynamicResource DynamicColor}"/>
    
  2. 在项目的某个文件夹中添加以下 3 个颜色画笔字典...

     <!-- Name = OrangeColorResource.xaml -->
     <ResourceDictionary 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
         <Color x:Key="DynamicColor">Orange</Color>
    </ResourceDictionary>
    
     <!-- Name = BlueColorResource.xaml -->
     <ResourceDictionary 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
         <Color x:Key="DynamicColor">Blue</Color>
    </ResourceDictionary>
    
     <!-- Name = RedColorResource.xaml -->
     <ResourceDictionary 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
         <Color x:Key="DynamicColor">Red</Color>
    </ResourceDictionary>
    

请注意,密钥保持不变,即DynamicColor.

  1. 现在清除并重新创建App.Resources. 我已经在后面的代码中做到了Window.xaml.cs

    private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        Application.Current.Resources.MergedDictionaries.Clear();
        Application.Current.Resources.MergedDictionaries.Add(
           new ResourceDictionary()
           { 
              Source = new Uri("Resources\\"
                               + ((ComboBox)sender).SelectedItem.ToString()
                               + "ColorResource.xaml",
                               UriKind.RelativeOrAbsolute) });
    }
    

现在,当您从下拉列表中选择一种颜色时,静态资源画笔上的动态颜色会发生变化。请注意,不涉及样式。

我希望这能回答你的问题。

于 2012-01-02T11:38:57.063 回答
0

顺便说一句:这篇文章的原因有一些更复杂的背景。我真的很想使用单个资源字典,从而可以在运行时(由最终用户)动态更改颜色、字体、字体大小等。我正在处理税表申请。屏幕上显示的供用户输入的税表正在应用程序级别解决他们的资源。到目前为止,一切都很好。

但同时我想向用户展示税表的打印预览,其中使用相同的资源字典(作为对象类型,而不是作为对象实例)来定义用于打印的配色方案、字体、字体大小等. 这可能与用于屏幕用户输入的样式不同。这就是为什么我想在(例如)FixedDocument 级别上“附加”资源字典,以便文档中的所有页面都可以引用它。并且在更改颜色、字体等时,所有具有公共元素(TextBlocks、TextEditors 等)的页面都会响应更改。

然后我被卡住了......如这篇文章中所述。

现在我有一个很好的解决方法,方法是创建资源字典的特定实例,将其存储为私有变量并将其附加到我放入固定文档中的每个单独页面。它有效,这已经让我高兴了。但是我的程序员的心还是有点痛,因为我宁愿使用资源字典的单个实例并将它放在某个顶级控件中,以便其中的所有控件都可以使用它。

作为程序员,我们也必须接受解决方法;)如果您有任何进一步的建议,我愿意接受。感谢您迄今为止的支持。

问候,乔普。

另请参阅:有关此问题的 MSDN 论坛帖子

于 2012-01-16T10:04:04.127 回答