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

Настройка цвета переднего плана всего окна

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

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

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

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

4b9b3361

Ответ 1

Это связано с тем, что такие элементы управления, как 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 inself). И в этом стиле по умолчанию переопределить свойство 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>

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

Ответ 2

К сожалению, как стили работают в 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>

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

EDIT:

Вы можете использовать метод Pavlo, приведенный ниже, для восстановления наследования и упрощения его использования следующим образом:

<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>

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

Ответ 3

Да, это не так просто в 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>

Ответ 4

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

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

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

<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>