2012-01-27 2 views
29

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

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

Размещения неявного стиля в Window.Resourcesdoes not cross control template boundaries , поэтому такие вещи, как 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

+0

Хороший вопрос и понимание о том, как неявные стили пересечения границы App.xaml ControlTemplate. Из-за этого я импортирую/объединяя определенные ресурсные словари в * каждый * из моих окон приложения (я действительно просто импортирую только один мастер-файл). Вы нашли лучший способ решить эту проблему, чем то, как я это делаю? (Было бы лучше иметь возможность просто импортировать его один раз - как мы это делаем с импортированными ресурсами App.xaml.) –

+0

Эта проблема с границей ControlTemplate особенно затруднительна для случаев, таких как (App.xaml-level) неявный TextBlock, где TextBlock автоматически генерируется как дочерний элемент ContentPresenter элемента управления. Используя трюк на уровне окна, который Рейчел упоминает, решил эту проблему для меня. –

+0

@Jason Обычно мои приложения WPF имеют только одно окно, при этом содержимое изменяется по мере необходимости. Я не думаю, что я когда-либо делал то, что было более двух окон (вход и приложение). Тем не менее, вы, вероятно, могли бы использовать MEF для импорта/экспорта ресурсных словарей, как описано [здесь] (http://stackoverflow.com/q/842571/302677) – Rachel

ответ

22

Это действительно единственная специальная обработка, добавленная в 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 элементов.

+1

Вы знаете, почему неявный стиль в «Application.Resources» переопределяет любой другой неявный стиль, определенный в «Ресурсах» любого другого элемента интерфейса? – Rachel

+1

@ Rachel - Я не верю, что это правда. Для элементов управления неявный стиль, определенный в Window.Resources, будет иметь приоритет над единицами в Application.Resources. Для UIElements, которые не выводятся из Control и которые используются в шаблоне, тогда Windows.Resources не запрашивается, поэтому в этом случае будут использоваться Application.Resources. – CodeNaked

+0

Вы правы, его единственные элементы пользовательского интерфейса, которые не происходят из 'Control', которые в любом случае не наследуются от неявных стилей. Спасибо :) – Rachel

1

Довольно равнине просто

Если вы хотите ресурсы для совместного использования ВСЕЙ приложения вы будете использовать Application.Resources

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

Если вы хотите ресурсы для совместного использования одного элемента управления вы будете использовать (Безотносительно Control) .resources

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

+1

Но я смущен, почему установка неявного стиля «TextBlock» в «Application.Resources» будет проходить через границы управления, когда поведение по умолчанию для неявных стилей не должно пересекать контрольные шаблоны, если только элемент, к которому применяется неявный стиль, относится к введите 'Control'. И до сих пор все мои приложения WPF содержались в одном окне, поэтому я всегда использую 'Window.Resources' – Rachel

+2

Я лично избегаю скрытых стилей, потому что это путало новых разработчиков в проекте. Скажем, у вас есть 100k строк кода или более с более чем 20 ресурсоемкими словарями, объединенными в App.xaml, и я добавляю неявный стиль в один из них. Ты собираешься сказать себе, если ты никогда не видел код ЧТО ГОВОРИТСЯ! !! Я могу видеть использование имплицитного стиля, возможно, в пользовательском USerControl, где его тест или викторина или что-то, где каждый TextBlock может иметь одинаковый запас. – MyKuLLSKI

+0

Я часто использую неявные стили, так как я ленив и не люблю определять именованные стили для абсолютно всех.Для меня довольно распространено, что неявные стили определяют маржу, выравнивание или цвета общих элементов управления в верхней части «View», хотя теперь, когда я думаю об этом, я не часто применяю неявные стили в приложении «Окно» 'или' Application' (конечно, неявные DataTemplates - это еще одна история) – Rachel

0

разница заключается в рамки стилей:

  • при размещении в Application.Resources, стиль будет применяются ко всем элементам управления в a РИМЕНЕНИЕ
  • при размещении внутри Windows.Resources, стиль будет применяться ко всем элементам управления в окне

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

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

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

+1

Это неправда. Если у вас есть 'Button' в' ControlTemplate' другого 'Control' (например,' TextBox'), тогда будет применен любой неявный стиль для 'Button' в Windows.Resources. – CodeNaked

0

Рейчел, я не думаю, что ничего особенного в «Стили». Более того, не существует вопроса о «пересечении границ шаблонов». Причина этого различна, и она переходит к различным «деревьям» в приложении WPF. По вашему вопросу я Recon вы изображая мир со следующей иерархией:
- Применение => 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 => Сетка => Кнопка => Строка

Объект TextBlock внутри кнопки является не является частью логического дерева (хотя это часть VisualTree).

Искание ресурсов осуществляется LogicalTree с разницей. После того, как он достигнет верхнего объекта, алгоритм поиска ресурса будет смотреть на ресурсный словарь , а затем на 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

В WPF используется специальная обработка для стилей, целевой тип которых не является результатом Control, например TextBlock. Как объясняет Рахиль, стиль TextBlock обрабатывается по-разному, если он помещен в Application.Resources versus Window. – CodeNaked

Смежные вопросы