Неявные стили в Application.Resources vs Window.Resources? - PullRequest
33 голосов
/ 27 января 2012

Я смотрел на этот вопрос и заметил, что размещение неявного стиля TextBlock в Application.Resources применяет этот стиль ко всем текстовым блокам, даже к тем, которые находятся внутри других элементов управления, таких как Buttons, ComboBoxesи т. д.

<Application.Resources>
    <Style TargetType="{x:Type TextBlock}">
        <Setter Property="Foreground" Value="Blue" />
    </Style>
</Application.Resources>

Размещение неявного стиля в Window.Resources не пересекает границы шаблона управления , поэтому такие вещи, как Buttons и ComboBoxes, сохраняют свой черный текст по умолчанию.

<Window.Resources>
    <Style TargetType="{x:Type TextBlock}">
        <Setter Property="Foreground" Value="Blue" />
    </Style>
</Window.Resources>

Кроме того, добавление стиля по умолчанию в Application.Resources делает его таким образом, что вы не можете перезаписать этот стиль другим неявным стилем.

<!-- Doesn't work if implicit style with same property is in Application.Resources -->
<ComboBox.Resources>
    <Style TargetType="{x:Type TextBlock}">
        <Setter Property="Foreground" Value="Red" />
    </Style>
</ComboBox.Resources>

Мои вопросы:

  • Почему это?
  • Есть ли другие различия между Application.Resources и Windows.Resources?
  • Когда следует использовать один над другим?

    Я понимаю, что Application.Resources применяется ко всему приложению, в то время как Window.Resources применяется только к окну, однако я хочу знать, почему стили в Application обрабатываются иначе, чем стили в Window

Ответы [ 4 ]

23 голосов
/ 07 февраля 2012

Это действительно единственная специальная обработка, добавленная в WPF, и она была сделана специально. Код, который его реализует, можно найти в FrameworkElement, в методе FindImplicitStyleResource, который эффективно выполняет:

internal static object FindImplicitStyleResource(FrameworkElement fe, object resourceKey, out object source)
{
        // ...
        DependencyObject boundaryElement = null;
        if (!(fe is Control))
            boundaryElement = fe.TemplatedParent;
        // ...
}

Таким образом, эмпирическое правило состоит в том, что неявные стили всегда применяются к элементам управления (то есть происходит от Control). Предполагая, что неявный Стиль может быть найден.

Для элементов, используемых в ControlTemplate, которые не являются производными от Control, таких как TextBlock, неявный поиск по стилю не будет пересекать его шаблонного родителя. В вашем случае выше, это будет ComboBox.

Я полагаю, что это было сделано для того, чтобы неявные неявные стили для TextBlock не были непреднамеренно применены к TextBlock элементам, используемым в шаблонах элементов управления, о которых разработчик мог знать, а может и не знать, что они были. Неявные стили будут применяться только к текстовым блокам, фактически созданным разработчиком в их собственном XAML.

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

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

Но имейте в виду, что это влияет на любой не Control элемент, такой как Shape elements.

2 голосов
/ 27 января 2012

Довольно просто, как просто

Если вы хотите, чтобы ресурсы использовались совместно с ВСЕМ приложением, вы бы использовали Application.Resources

Если вы хотите, чтобы ресурсы были распределены между всем окномвы бы использовали Window.Resources

Если вы хотите, чтобы ресурсы были распределены между одним элементом управления, который вы бы использовали (независимо от того, какой элемент управления).стиль в одном, а не в другом, то вы бы использовали Windoe.Resources

0 голосов
/ 04 февраля 2012

Рэйчел, я не думаю, что есть что-то особенное для "Стилей".Более того, нет проблемы «пересечения границ шаблона».Причина этого в другом, и это относится к разным «деревьям» в приложении WPF.По вашему вопросу, я полагаю, вы представляете мир со следующей иерархией:
- Приложение => Окно => Элемент управления => Элементы внутри элемента управления

Такой иерархии не существует.В приложении WPF есть разные деревья, наиболее известными из них являются Логическое дерево и Визуальное дерево, но есть и другие (дерево событий маршрутизации, а также дерево поиска ресурсов с немного другой семантикой).

Предположим, чтоследующий XAML:

<Window x:Class="SO.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>
        <Button x:Name="btn" Click="click">Click Me</Button>
    </Grid>
</Window>

Для этого XAML логическое дерево будет выглядеть так:- Window => Grid => Button => String

Текстовый блок внутри кнопки не является частью логического дерева (хотя является частью VisualTree).

Поиск ресурсов идетпо логическому дереву, с одним отличием.После того, как он достигнет верхнего объекта, алгоритм поиска ресурсов будет искать словарь ресурсов Application , затем каталог ресурсов Theme , а затем System словарь ресурсов в следующем порядке.

Смотрите следующие статьи:

Finnaly, чтобы доказать мою точку зрения, добавьте в приложение XAML следующий ресурс:

<Application x:Class="SO.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:clr="clr-namespace:System;assembly=mscorlib"
    StartupUri="MainWindow.xaml">
    <Application.Resources>
        <clr:String x:Key="MyResource">Hello Application Resource</clr:String>
    </Application.Resources>
</Application>

и следующий код:

private void click(object sender, RoutedEventArgs e)
{
    // Logical Children of btn
    Debug.WriteLine("Children of btn:");
    foreach( var x in LogicalTreeHelper.GetChildren(btn) ) {
        Debug.WriteLine("{0} : {1}", x, x.GetType());
    }

    // Walk the visual tree
    Debug.WriteLine("The Visual Tree:");
    WalkVisual(0, this);

    // Find the textblock within the button
    DependencyObject p = btn;
    while (p.GetType() != typeof(TextBlock))
        p = VisualTreeHelper.GetChild(p, 0);
     TextBlock tb = p as TextBlock;

    // Now climp the textblock through the logical tree
    while (p != null)
    {
        Debug.WriteLine("{0}", p.GetType());
        p = LogicalTreeHelper.GetParent(p);
    }

    // Find a resource for the textbox
    string s = tb.FindResource("MyResource") as string;
    Debug.WriteLine("MyResource Content: {0}", s);
}

private void WalkVisual(int indent, DependencyObject p)
{
    string fmt = string.Format("{{0,{0}}}{{1}}", indent * 4);
    Debug.WriteLine(fmt, "", p.GetType());
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(p); ++i)
    {
        WalkVisual(indent+1,VisualTreeHelper.GetChild(p, i));
    }
}

Итак ... как только вы поймете первый вопрос («почему это так»), остальные вопросы развалится.Различие между ресурсами приложения и ресурсами окна заключается в том, что ресурсы приложения могут быть найдены любым DependencyObject в вашем приложении, включая те, которые определены в других сборках.Вы будете использовать его, когда хотите получить: -)

u.

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

Разница заключается в объеме стилей:

  • при размещении в Application.Resources стиль будет применяться ко всем элементам управления в приложении
  • при размещении внутри Windows.Ресурсы, стиль будет применяться ко всем элементам управления в окне

Разница довольно тонкая, но это означает, что любой элемент управления, о котором мы говорим (включенный в шаблон другого элемента управления)получит стиль из приложения. Ресурсы.но только элементы управления непосредственно дочерние элементы окна получат стиль из окна. Ресурсы.Элемент управления внутри шаблона другого элемента управления не будет иметь стиль, определенный в Window.Resources, поскольку он не находится непосредственно в окне, тогда как у него будет стиль, определенный в Application.Resources, поскольку он находится в приложении.

какдля вашего второго пункта, это связано с приоритетом свойства зависимости, я думаю:

http://msdn.microsoft.com/en-us/library/ms743230.aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...