Динамический поиск ресурсов в WPF с помощью FixedPage - PullRequest
1 голос
/ 02 января 2012

Наличие следующего очень простого 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>

Использование динамических ресурсов (которые мне действительно нужны в более сложной ситуации) здесь не работает.Используя Static Resources, цвета TextBlocks получают желаемыми цветами.Перемещение ресурсов на уровень FixedPage также делает свое дело.Но я хотел бы иметь один общий словарь ресурсов для элемента верхнего уровня (из-за изменений во время выполнения, которые пользователь может сделать для цветов, шрифтов и т. Д.).Размещение ресурсов на уровне приложения также работает.Но это не вариант по веским причинам.

Кто-нибудь может понять, почему это не работает.Это как-то связано с логическим деревом от TextBlock и выше?

Обзор ресурсов MSDN гласит:

Процесс поиска проверяет наличие запрошенного ключа в словаре ресурсов, заданном элементом, который устанавливает свойство.

  • Если элемент определяет свойство Style, проверяется словарь ресурсов в Style.
  • Если элемент определяет свойство Template, проверяется словарь ресурсов в FrameworkTemplate.

Затем процесс поиска переходит логическое дерево вверх к родительскому элементу и его словарю ресурсов.Это продолжается до тех пор, пока не будет достигнут корневой элемент.

Я также попытался поместить кисть и стиль в ресурсы (фиктивного) стиля в соответствии с приведенным выше объяснением MSDN.Но это тоже не сработало.

Действительно есть ощущение, что это не может быть таким сложным, но, скорее всего, я что-то наблюдаю.Любая помощь приветствуется.

РЕДАКТИРОВАТЬ

При присвоении TextBlock имени "tb" и последующем использовании tb.FindResource ("TestStyle") выдает исключение.Так что этот ресурс явно не может быть найден.Если я проверяю LogicalTreeHelper.GetParent (tb) и повторяю, что для найденных родителей я получаю ожидаемый результат: TextBlock> FixedPage> PageContent> 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).Также использование TryFindResource в коде позади работает с pc (PageContent), но с fp (FixedPage) и tb (TextBlock) не может разрешить ресурс (obj равен null).При использовании статического ресурса в разметке XAML все работает нормально.

Ответы [ 2 ]

0 голосов
/ 16 января 2012

Кстати: причина этого поста была несколько более сложная.Я действительно хотел использовать один словарь ресурсов, с помощью которого я мог бы динамически изменять цвета, шрифты, размеры шрифтов и т. Д. Во время выполнения (конечным пользователем).Я работаю над заявкой на налоговую форму.И налоговые формы, представленные на экране для пользовательского ввода, разрешают их ресурсы на уровне приложений.Пока все хорошо.

Но в то же время я хочу представить пользователю предварительный просмотр налоговой формы, в которой для определения цветовых схем используется один и тот же ресурсный словарь (как тип объекта, а не экземпляр объекта),шрифты, размеры шрифтов и т. д., которые будут использоваться для печати.Который может отличаться от стиля, используемого для пользовательского ввода на экране.Вот почему я хотел «прикрепить» словарь ресурсов к (например) уровню FixedDocument, чтобы все страницы документа ссылались на него.И при изменении цвета, шрифтов и т. Д. Все страницы с общими элементами (TextBlocks, TextEditors и т. Д.) Будут реагировать на изменение.

И тогда я застрял ... как описано в этом посте.

Пока у меня есть хороший обходной путь, создавая конкретный экземпляр ресурса, сохраняя его как частную переменную и прикрепляя его к каждой отдельной странице, которую я помещаю в фиксированный документ.Это работает, и это уже радует меня.Но мое сердце программистов все еще немного болит, потому что я предпочел бы использовать один экземпляр словаря ресурсов и поместить его в какой-то элемент управления верхнего уровня, чтобы все элементы управления в нем могли использовать его.

Как программист мыпридется обходиться обходными путями;) Если у вас есть какие-либо дополнительные предложения, я открыт для их получения.Спасибо за вашу поддержку.

Greetz, Joep.

См. Также: Сообщение на форуме MSDN об этой проблеме

0 голосов
/ 02 января 2012

Хорошо придерживаться стиля - хороший дизайн, но не обязательный.Для создания динамических цветных кистей с тем же именем (с ключом) мы можем использовать словари динамических цветов ( NOT словари кистей)

Решение может быть таким, как показано ниже ...

  1. Создать словарь ресурсов для одной кисти.
  2. Назовите цвет кисти с атрибутом DynamicResource.
  3. Создайте несколько словарей ресурсов с одинаковым ключевым Color ресурсом в каждом из них.
  4. В зависимости от требований пользователя очистить и добавить в Application.Current.resources.MergedDictionaries.

Пример

  1. Сделать WPFпроект с окном, которое имеет следующий XAML ....

     <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) });
    }
    

Теперь, когда вы выбираете цвет из выпадающего списка, динамический цвет изменяется на кисти статического ресурса.Обратите внимание, что Стиль не задействован.

Я надеюсь, что это отвечает на ваши вопросы.

...