Подтвердить что ты не робот

Неявные стили в Application.Resources vs Window.Resources?

Я смотрел этот вопрос и заметил, что размещение неявного стиля TextBlock в Application.Resources применяет этот стиль ко всем TextBlocks, даже к тем, которые находятся внутри других элементов управления, таких как как 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

4b9b3361

Ответ 1

Это действительно единственная специальная обработка, добавленная в 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, которые использовались в шаблонах управления, которые разработчик мог или не мог знать. Неявные стили будут применяться только к TextBlocks, фактически созданным разработчиком в их собственном XAML.

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

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

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

Ответ 2

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

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

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

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

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

Ответ 3

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

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

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

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

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

Ответ 4

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

Нет такой иерархии. В приложении 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, хотя).

Поиск ресурсов идет по LogicalTree с разницей. После того, как он достигнет верхнего объекта, алгоритм поиска ресурсов будет искать словарь ресурсов приложения, а затем в разделе "Ресурс темы", а затем в словаре ресурсов системы в этом порядке.

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

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 в вашем приложении, в том числе и в других сборках. Вы будете использовать его, если это то, что вы хотите добиться: -)

и.