2

項目タイプによって定義された Label、TextBox などのデフォルト スタイルのセットが付属する WPF アプリケーションがあります (明示的なキーは定義されていません)。

アプリケーション内では、暗い背景色と明るい背景色の 2 つの主要なコンテナーが使用されます。そのため、ラベルの前景色として黒を使用することが正しい場合もあれば、極端に間違っている場合もあります。一方、エディターは常に明るい背景と暗い前景というかなり伝統的なスタイルになっているため、すべての子要素の前景を逆に設定することはできません。

「自分の」背景に応じて前景色を決定するために、ラベル (およびおそらく TextBlocks も) を作成するエレガントな方法はありますか? 私は2つの色を切り替えたいだけなので、自動コントラストの最大化は必要ありません。白い地面に白いフォントを避けるためのしきい値だけです。

また、デフォルト スタイルの 2 つのセットを定義したくありません。単一の Label-Default-Style を両方の背景バリアントに適したものにする方法を強く探しています。

現在の背景色を評価するトリガー/バインディングをスタイルに追加することは可能ですか (そして、パフォーマンスにあまり影響を与えずに実現可能ですか)?

または、上記の問題に遭遇することなく、特定の FrameworkElements、特にコンテナー/パネルの背景色をきれいに設定する方法のベスト プラクティスに興味があります。

これが私が試したことです(もちろん単純化されています):

  <UniformGrid>
  <UniformGrid.Resources>
  <!-- SimpleStyles: Label -->
     <Style x:Key="{x:Type Label}" TargetType="{x:Type Label}">
        <Setter Property="HorizontalContentAlignment" Value="Left"/>
        <Setter Property="VerticalContentAlignment" Value="Top"/>
        <Setter Property="Template">
           <Setter.Value>
              <ControlTemplate TargetType="{x:Type Label}">
                 <Border>
                    <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" RecognizesAccessKey="True"/>
                 </Border>
                 <ControlTemplate.Triggers>
                    <Trigger Property="Background" Value="Black">
                       <Setter Property="Foreground" Value="Red"/>
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="false">
                       <Setter Property="Foreground" Value="#888888"/>
                    </Trigger>
                 </ControlTemplate.Triggers>
              </ControlTemplate>
           </Setter.Value>
        </Setter>
     </Style>
  </UniformGrid.Resources>
  <Label x:Name="bgSetExplicitly" Background="Black">abc
  </Label>
  <Border Background="Black">
     <Label x:Name="bgInheritedFromParent" >abc
     </Label>
  </Border>
  <Label>abc
  </Label>
  <Label>abc
  </Label>

ラベルに明示的な背景セット (x:Name=bgSetExplicitly) がある場合、ラベルの背景が適切に選択されていることがわかりますが、背景が VisualTree の親から「継承」されている場合 (x:Name="bgInheritedFromParent") 、 そうではありません。スタイルが「効果的な背景」(それがどこから来ても) を評価し、この背景に適切な前景ブラシを選択できるようにしたいと考えています。

4

3 に答える 3

4

この質問は、より深い問題を暗示しているようです。前景色の管理を統合していないため、前景色をあらゆる場所に設定するコードまたはスタイルを持つアプリケーションがあると思います。そして今、あなたはその影響の1つに取り組んでいます。

私はより深い問題に直面し、それを修正します。あなたがデフォルト スタイルを作成するという考えに抵抗する理由はよくわかりませんが、現時点では、これを行わない正当な理由があると仮定します (「ある時点でデフォルト スタイルを作成する必要があったが、今はそれがなく、アプリケーションが大きくなってしまったので、大変です」という場合は、別の提案があります)、グローバル リソースを作成するのはどうですか?

コントロールの前景色と背景色のオブジェクトをアプリケーションのリソース ディクショナリに作成し、XAML を修正して、ブラシを直接参照する代わりに、DynamicResourceマークアップ拡張機能を使用してリソース ディクショナリからブラシを取得します。コードではForeground、コントロールのプロパティをブラシに直接設定する代わりに、 を使用GetResourceしてブラシを取得します。背景も同じように設定します。

これが完了したら、アプリケーションで前景色/背景色をグローバルに変更したい場合は、リソースを変更するだけです。

これは基本的に、WPF アプリケーションをスキン可能にする方法です。

于 2011-05-31T16:15:39.850 に答える
3

最も簡単な方法は、TextBoxなどの前景色をそれらを含む要素の背景にバインドし、値コンバーターを使用して変更を加えることです。これは、2色しか使用していない場合に特に簡単です。

例として...

  public class ColorSwapper : IValueConverter
  {
    public object Convert(object value, Type targetType, object parameter, 
System.Globalization.CultureInfo culture)
    {
      if (value == null) { return DependencyProperty.UnsetValue; }

      Color srcColor = (value as SolidColorBrush).Color;
      if (srcColor == Colors.Black)
      {
        return new SolidColorBrush(Colors.White);
      }
      else
      {
        return new SolidColorBrush(Colors.Black);
      }
    }
...

そして、いくつかの例のXAML...。

<Grid Grid.Column="1" Name="RightGrid" Background="White">
  <TextBlock Text="Hello Nurse!" Foreground="{Binding ElementName=RightGrid, Path=Background, Converter={StaticResource ColorSwapper}}"/>
</Grid>

もちろん、特定のニーズに応じて微調整やクリーンアップを行うこともできますが、それで十分です。

于 2011-05-31T11:59:17.243 に答える
0

別の可能なアプローチを次に示します。アプリケーションにすべての暗い/明るい背景とその賛辞しかない場合は、他の回答で言及した「ColorSwapper」を使用して、このようなアプローチを試すことができます。

<Window>
  <Window.Resources>
    <local:ColorSwapper x:Key="swapper"/>

    <SolidColorBrush x:Key="BackBrush" Color="Black"/>
    <!--<SolidColorBrush x:Key="BackBrush" Color="White"/>-->

    <Style TargetType="{x:Type TextBlock}">
      <Setter Property="Foreground" Value="{Binding Source={StaticResource BackBrush}, Converter={StaticResource swapper}}"/>
    </Style>

  </Window.Resources>

  <Grid Background="{StaticResource BackBrush}">
    <TextBlock FontSize="24" FontWeight="Bold">ABC</TextBlock>
  </Grid>
</Window>

これで、'BackBrush' の色の値を変更するたびに、関連するすべての前景色が自動的に更新されます。あなたの議論に基づいて、これもあなたのスタイル要件を満たすと思います. いずれにせよ、このアプローチが正確なシナリオに適合するようにするには、小さな改造を行う必要があるでしょう。

于 2011-06-01T12:32:54.403 に答える