Установка цвета переднего плана всего окна - PullRequest
23 голосов
/ 16 марта 2011

Я хотел бы установить цвет переднего плана (текста) для всех моих элементов Вы могли бы подумать, что это будет легко, но это не так ...

<Window Foreground="Red">
   <Label Content="Test"/>
   <Label Content="Test"/>
   <CheckBox Content="Checkbox"/>
</Window>

Это не имеет никакого эффекта ... Единственный способ заставить это работать, если я специально устанавливаю свойство Foreground для каждого из элементов. И это раздражает, если у вас есть сотни элементов и т. Д.

Может быть, вы знаете способ?

Ответы [ 4 ]

26 голосов
/ 16 марта 2011

Это связано с тем, что такие элементы управления, как Label и CheckBox, переопределяют свойство Foreground в своих стилях.

Ниже приведен пример типичного логического дерева элементов, которое показывает, как значение, указанное на уровне Window, перемещается по дереву:

Window (Red [Local]) 
  -> Grid (Red [Inherited]) 
     -> ListBox (Red [Inherited]) 
        -> ListBoxItem (Red [Inherited]) 
           -> StackPanel (Red [Inherited]) 
              -> Label (Black [Style])
                 -> TextBlock (Black [Inherited])
              -> TextBlock (Red [Inherited])

В квадратных скобках источникпоказано значение.

Как вы можете видеть разрывы наследования на самом Label, потому что у него установлено свойство Foreground в его стиле по умолчанию:

<Style x:Key="{x:Type Label}"
       TargetType="{x:Type Label}">
    <Setter Property="Foreground"
            Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
    ...
</Style>

В качестве обходного пути для этого мы можем использовать следующий прием.Определите стиль по умолчанию для таких элементов управления (например, Label) в приложении (в файле App.xaml или в самом файле Window).И в этом стиле по умолчанию переопределите свойство Foreground, чтобы установить относительную привязку источника к ближайшему предку элемента управления, который все еще имеет желаемое значение:

<Style TargetType="{x:Type Label}">
    <Setter Property="Foreground"
            Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type FrameworkElement}}, Path=(TextElement.Foreground)}"/>
</Style>

<Style TargetType="{x:Type CheckBox}">
    <Setter Property="Foreground"
            Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type FrameworkElement}}, Path=(TextElement.Foreground)}"/>
</Style>

После этого наше дерево будет выглядеть так:

Window (Red [Local]) 
  -> Grid (Red [Inherited]) 
     -> ListBox (Red [Inherited]) 
        -> ListBoxItem (Red [Inherited]) 
           -> StackPanel (Red [Inherited]) 
              -> Label (Red [Binding to StackPanel.(TextElement.Foreground)])
                 -> TextBlock (Red [Inherited])
              -> TextBlock (Red [Inherited])

Как видите, наша привязка восстанавливает наследование.

Такие стили необходимо определить для каждого элемента, который переопределяет свойство Foreground в своем стиле.Как предложил @Duane, чтобы не дублировать привязку в каждом стиле, можно использовать возможность BasedOn:

<Style x:Key="ForegroundInheritanceFixStyle"
       TargetType="Control">
    <Setter Property="Foreground"
            Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type FrameworkElement}}, Path=(TextElement.Foreground)}"/>
</Style>

<Style TargetType="{x:Type Label}"
       BasedOn="{StaticResource ForegroundInheritanceFixStyle}">
</Style>

<Style TargetType="{x:Type CheckBox}"
       BasedOn="{StaticResource ForegroundInheritanceFixStyle}">
</Style>

Надеюсь, это поможет.

6 голосов
/ 16 марта 2011

К сожалению, как работают стили в WPF, вы не можете создать общий стиль для родительского класса и применить его к подклассу управления.

Одна вещь, которую вы можете сделать, это создать базовый стильэто предназначается для базового типа со свойством, которое вы хотите установить (например, ContentControl), а затем создаете определенный стиль для каждого элемента управления, который основан на этом стиле.Вот пример:

<Window>
    <Window.Resources>

        <Style x:Key="BaseContentControlStyle" TargetType="{x:Type ContentControl}">
            <Setter Property="Foreground" Value="Red" />
        </Style>

        <Style TargetType="{x:Type Label}" BasedOn="{StaticResource BaseContentControlStyle}" />

        <Style TargetType="{x:Type CheckBox}" BasedOn="{StaticResource BaseContentControlStyle}" />

    </Window.Resources>

    <StackPanel>
        <Label Content="Test"/>
        <Label Content="Test"/>
        <CheckBox Content="Checkbox"/>
    </StackPanel>   
</Window>

Надеюсь, это поможет.

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

Вы можете использовать метод Павло ниже для восстановления наследования и сделать его немного проще, какитак:

<Window.Resources>

    <Style x:Key="BaseContentControlStyle" TargetType="{x:Type Control}">
        <Setter Property="Foreground" Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type FrameworkElement}}, Path=(TextElement.Foreground)}"/>
    </Style>

    <Style TargetType="{x:Type Label}" BasedOn="{StaticResource BaseContentControlStyle}" />

    <Style TargetType="{x:Type CheckBox}" BasedOn="{StaticResource BaseContentControlStyle}" />

</Window.Resources>

По крайней мере, тогда вам не нужно везде копировать один и тот же установочный код (кстати, я думаю, что TextBlock наследуется по умолчанию; нет стиля по умолчанию с переопределениями).

0 голосов
/ 16 марта 2011

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

В этом случае вы можете создать стили для своих типов и установить там цвета переднего плана.

В идеале это может быть ResourceDictionary, и каждый стиль будет ссылаться на общий цвет переднего плана, например * 1008.*

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <SolidColorBrush x:Key="appForegroundColor" Color="Red" />

    <Style TargetType="{x:Type TextBlock}">
        <Setter Property="Foreground" Value="{StaticResource appForegroundColor}" />
    </Style>

    <!-- Create styles for Element Types here -->

</ResourceDictionary>

Затем вы применяете этот словарь ресурсов к нужным окнам, например:

<Window ...>
    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Dictionary1.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>

    <Grid>
        <TextBlock Text="Foo" />
    </Grid>
</Window>
0 голосов
/ 16 марта 2011

Да, это не легко в wpf. Но вы можете попробовать вот так

<StackPanel>
        <StackPanel.Resources>
            <Style x:Key="CommonStyle">
                <Setter Property="TextElement.Foreground" Value="Red" />
            </Style>
        </StackPanel.Resources>
        <Label Content="Test" Style="{StaticResource CommonStyle}" />
        <Label Content="Test" Style="{StaticResource CommonStyle}"/>
        <CheckBox Content="Checkbox" Style="{StaticResource CommonStyle}"/>

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