繁体   English   中英

具有FixedPage的WPF动态资源查找行为

[英]WPF Dynamic Resource Lookup Behavior with FixedPage

具有以下非常简单的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的说明,将“画笔”和“样式”放入(虚拟)样式的资源中。 但这也不起作用。

确实有种感觉,那就不可能那么复杂,但是我很可能监督了一些事情。 任何帮助表示赞赏。

编辑

将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级别)。 也可以在pc(PageContent),但从fp(FixedPage)和tb(TextBlock)的代码中使用TryFindResource进行工作,但它无法解析资源(obj为null)。 在XAML标记中使用静态资源时,一切正常。

顺其自然的风格是一个好的设计,但不是必需的。 要制作基于动态颜色的相同命名(键控)笔刷,我们可以将其用作动态颜色词典( 而非笔刷词典)

解决方案可以如下

  1. 创建一个画笔资源字典。
  2. 使用DynamicResource属性引用画笔中的颜色。
  3. 创建多个具有相同键控Color资源的资源字典。
  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后面的代码中完成了此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) }); } 

现在,当您从下拉菜单中选择一种颜色时,动态颜色会在静态资源画笔上更改。 请注意,不涉及样式

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

顺便说一句:这篇文章的原因有一些更复杂的背景。 我真的很想使用一个资源字典,从而可以在运行时(由最终用户)动态更改颜色,字体,字体大小等。 我正在研究报税表。 屏幕上显示的供用户输入的税单正在应用程序级别解析其资源。 到现在为止还挺好。

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

然后我陷入了困境……正如这篇文章中所述。

现在,我有一个不错的解决方法,即创建资源字典的特定实例,将其存储为私有变量,并将其附加到我放入固定文档中的每个页面上。 它起作用了,这已经使我感到高兴。 但是我的程序员的心仍然有些痛苦,因为我更喜欢使用资源字典的单个实例,并将其放在某个顶级控件中,以便其中的所有控件都可以使用它。

作为程序员,我们也必须忍受变通方法;)如果您有任何其他建议,我愿意接受。 感谢您到目前为止的支持。

格蕾兹,乔普。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM