使用FixedPage的WPF动态资源查找行为

时间:2012-01-02 10:40:54

标签: wpf resourcedictionary staticresource dynamicresource

拥有以下非常简单的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着色。将Resources移动到FixedPage的级别也可以解决问题。但是我希望在顶级元素上有一个通用资源字典(因为用户可以对颜色,字体等进行运行时更改)。将资源放在应用程序级别上也可以正常工作。但出于好的理由,这不是一个选择。

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

MSDN Resources Overview声明:

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

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

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

我还尝试根据MSDN的上述说明将Brush和Style放入(虚拟)样式的资源中。但那也不起作用。

真的感觉这不是那么复杂,但很可能我会监督一些事情。任何帮助表示赞赏。

修改

将TextBlock命名为“tb”然后使用tb.FindResource(“TestStyle”)会抛出异常。所以资源显然无法找到。如果我查看LogicalTreeHelper.GetParent(tb)并重复发现父母找到的结果我得到了预期的结果:TextBlock&gt;固定页面&gt; PageContent&gt; FixedDocument ......

EDIT2

这很完美。与之前预测的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>

EDIT3

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

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

2 个答案:

答案 0 :(得分:0)

很好的风格方式是一个很好的设计,但没有必要。要使基于动态颜色的相同命名(键控)画笔,我们可以使用动态颜色词典(刷词典)

解决方案如下......

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

    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>        
      

    2. 如果您发现窗口不需要使用动态的任何。所有参考都可以保持不变。因此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>
        
      3. 请注意,保持不变,即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) });
          }
          
        2. 现在,当您从下拉列表中选择颜色时,静态资源画笔上的动态颜色会发生变化。请注意,没有涉及样式

          我希望这能回答你的要求。

答案 1 :(得分:0)

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

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

然后我陷入困境......如本文所述。

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

作为程序员,我们也必须忍受变通办法;)如果您有任何进一步的建议,我愿意接受它们。到目前为止,Thanx对你的支持。

Greetz,Joep。

另见:MSDN Forum Post about this issue