更改前景色动态地根据背景颜色 [英] Change foreground color dynamically based on background color

查看:173
本文介绍了更改前景色动态地根据背景颜色的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题域:在我的WPF应用程序,我改变很多背景的UI控件(例如Button)或动态基于它们所包含的数据ListItems的。既可以当控件加载或基于使用的动作/接收数据的背景被改变。

问题陈述:如果背景太暗(绿/蓝)我想前景设置为白色黑色别的

限制:我有一个大的应用和性能是一个主要问题。这就是为什么我很犹豫使用转换器和正在寻找一些XAML /风格触发基础的解决方案,因为这仅仅是一个基于状态的问题。

解决方案试图:为了简单起见,我解释什么我尝试了一个简单的WPF按钮:

 < UserControl.Resources>
<风格X:键=NoChr​​omeButton的TargetType ={X:类型按钮}>
        < setter属性=背景VALUE ={结合背景}/>
        < setter属性=OverridesDefaultStyleVALUE =真/>
        < setter属性=了borderThicknessVALUE =1/>
        < setter属性=BorderBrushVALUE =白/>
        < setter属性=Horizo​​ntalContentAlignmentVALUE =中心/>
        < setter属性=VerticalContentAlignmentVALUE =中心/>
        < setter属性=填充VALUE =1/>
        < setter属性=模板>
            < Setter.Value>
                <的ControlTemplate的TargetType ={X:类型按钮}>
                    <电网X:名称=铬
                          背景={TemplateBinding背景}
                          SnapsToDevicePixels =真
                          的Horizo​​ntalAlignment =拉伸>
                    <的TextBlock
                        文本={绑定的RelativeSource = {的RelativeSource TemplatedParent},路径=内容}
                        的Horizo​​ntalAlignment ={TemplateBinding Horizo​​ntalContentAlignment}
                                          保证金={TemplateBinding填充}
                                          背景={绑定的RelativeSource = {的RelativeSource TemplatedParent},路径=背景}
                                          SnapsToDevicePixels ={TemplateBinding SnapsToDevicePixels}
                                          VerticalAlignment ={TemplateBinding VerticalContentAlignment}
                        风格={StaticResource的MyTextBlockStyle}/>
                    < /网格和GT;
                    < ControlTemplate.Triggers>
                        <触发属性=IsMouseOverVALUE =真>
                            < setter属性=背景VALUE =黑/>
                        < /触发>
                        <触发属性=背景值=白>
                            < setter属性=前景VALUE =水族/>
                        < /触发>
                        <触发属性=背景值=透明>
                            < setter属性=前景VALUE =蓝紫/>
                        < /触发>
                        <触发属性=背景值=绿色>
                            < setter属性=前景VALUE =蓝/>
                        < /触发>
                        <触发属性=背景值=黄色>
                            < setter属性=前景VALUE =红/>
                        < /触发>
                        <触发属性=背景值=红>
                            < setter属性=前景VALUE =黄色/>
                        < /触发>
                        <触发属性=背景值=黑>
                            < setter属性=前景VALUE =深海藻绿/>
                        < /触发>
                    < /ControlTemplate.Triggers>
                < /控件模板>
            < /Setter.Value>
        < /二传手>        <风格X:键=MyTextBlockStyle的TargetType =TextBlock的>
    < setter属性=字号VALUE =12/>
    < setter属性=fontstyle的VALUE =斜体/>
    < Style.Triggers>
        <触发属性=背景值=白>
            < setter属性=前景VALUE =水族/>
        < /触发>
        <触发属性=背景值=透明>
            < setter属性=前景VALUE =蓝紫/>
        < /触发>
        <触发属性=背景值=绿色>
            < setter属性=前景VALUE =蓝/>
        < /触发>
        <触发属性=背景值=黄色>
            < setter属性=前景VALUE =红/>
        < /触发>
        <触发属性=背景值=红>
            < setter属性=前景VALUE =黄色/>
        < /触发>
        <触发属性=背景值=黑>
            < setter属性=前景VALUE =深海藻绿/>
        < /触发>
< /样式和GT;
< /UserControl.Resources>

当在XAML中创建按钮:

 <按钮内容={绑定名称}风格={StaticResource的NoChr​​omeButton}/>

另外,我想指出的几件事情在上面的风格:


  1. 如果我会用一个名为Chrome的网格内的内容presenter而不是TextBlock的背景属性未设置​​在内容presenter,当我探听(的 HTTP://snoopwpf.$c$cplex.com/ )的UI,我发现内容presenter拥有的TextBlock其背景总是设置为默认值,因此没有styletriggers被应用到TextBlock。此外,该TextBlock的背景values​​ource是默认的。

在另一方面,当我使用的TextBlock直接点名镀铬网格里面,我可以明确地设置它的背景被设置为按钮背景网格的背景。侦听显示,现在的TextBlock的背景ValueSource是ParentTemplate。


  1. 按钮,同时显示其内容拿起MyTextBlockStyle。


  2. 样式将触发按钮或TextBlock中从未被触发,除非我做鼠标移到它改变了按钮的背景为黑色,并传播这种价值减记至TextBlock的背景改变文本块的前景色为深海藻绿的按钮。


  3. 此外,更改按钮在snoop实用程序后台,同时应用程序运行时,触发式触发器。


问题:


  1. 为什么没有伴奏的触发器Background属性的工作,而他们的IsMouseOver物业工作?


  2. 我做错了吗?


  3. 这个解决的办法?



解决方案

我找到了解决我的问题。
TextBlock中没有从控制派生。任何控制界面上显示任何文本内部使用的TextBlock重新present的文本内容。如果TextBlock的风格是使用下面的一组中的ResourceDictionary:

 <风格的TargetType =TextBlock的>
    < setter属性=的FontFamilyVALUE =宋体/>
    < setter属性=字号VALUE =12/>
    < setter属性=fontstyle的VALUE =正常/>
< /样式和GT;

这再次presents文字都会有这样的风格(因为没有钥匙被分配给这种风格,这意味着所有的TextBlock将默认得到它),除非该控件的模板覆盖这是可以做到文本块的默认样式的控制如下:

 <按钮Grid.Column =1样式={StaticResource的NoChr​​omeButton}>
    < TextBlock的风格={X:空}文本=ABC的FontFamily =濑越UI符号/>
< /按钮>

这个简单的设置已经解决了大部分我们与动态前景色变化的问题​​。

Problem domain: In my WPF application, I change background of lot of UI controls like Button or ListItems dynamically based on data they contain. The background is changed either when the control is loaded or based on use action/data received.

Problem statement: If the background is too dark (Green/Blue) I want to set the foreground to white else black.

Constraints: I have a big application and performance is a major concern. That's why I am hesitant to use converters and am looking for some xaml/style trigger based solutions as this is just a condition based issue.

Solutions tried: To keep it simple, I am explaining what I tried for a simple wpf button:

<UserControl.Resources>
<Style x:Key="NoChromeButton" TargetType="{x:Type Button}">
        <Setter Property="Background" Value="{Binding Background}"/>
        <Setter Property="OverridesDefaultStyle" Value="True"/>
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="BorderBrush" Value="White"/>
        <Setter Property="HorizontalContentAlignment" Value="Center"/>
        <Setter Property="VerticalContentAlignment" Value="Center"/>
        <Setter Property="Padding" Value="1"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Grid x:Name="Chrome" 
                          Background="{TemplateBinding Background}" 
                          SnapsToDevicePixels="true"
                          HorizontalAlignment="Stretch">
                    <TextBlock 
                        Text="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Content}"
                        HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                                          Margin="{TemplateBinding Padding}" 
                                          Background="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Background}"
                                          SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" 
                                          VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                        Style="{StaticResource MyTextBlockStyle}"/>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter Property="Background" Value="Black"/>
                        </Trigger>
                        <Trigger Property="Background" Value="White">
                            <Setter Property="Foreground" Value="Aqua"/>
                        </Trigger>
                        <Trigger Property="Background" Value="Transparent">
                            <Setter Property="Foreground" Value="BlueViolet"/>
                        </Trigger>
                        <Trigger Property="Background" Value="Green">
                            <Setter Property="Foreground" Value="Blue"/>
                        </Trigger>
                        <Trigger Property="Background" Value="Yellow">
                            <Setter Property="Foreground" Value="Red"/>
                        </Trigger>
                        <Trigger Property="Background" Value="Red">
                            <Setter Property="Foreground" Value="Yellow"/>
                        </Trigger>
                        <Trigger Property="Background" Value="Black">
                            <Setter Property="Foreground" Value="DarkSeaGreen"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>

        <Style x:key="MyTextBlockStyle" TargetType="TextBlock">
    <Setter Property="FontSize" Value="12"/>
    <Setter Property="FontStyle" Value="Italic"/>
    <Style.Triggers>
        <Trigger Property="Background" Value="White">
            <Setter Property="Foreground" Value="Aqua"/>
        </Trigger>
        <Trigger Property="Background" Value="Transparent">
            <Setter Property="Foreground" Value="BlueViolet"/>
        </Trigger>
        <Trigger Property="Background" Value="Green">
            <Setter Property="Foreground" Value="Blue"/>
        </Trigger>
        <Trigger Property="Background" Value="Yellow">
            <Setter Property="Foreground" Value="Red"/>
        </Trigger>
        <Trigger Property="Background" Value="Red">
            <Setter Property="Foreground" Value="Yellow"/>
        </Trigger>
        <Trigger Property="Background" Value="Black">
            <Setter Property="Foreground" Value="DarkSeaGreen"/>
        </Trigger>
</Style>
</UserControl.Resources>

When button is created in the XAML:

  <Button Content="{Binding Name}" Style="{StaticResource NoChromeButton}"/>

Also, I would like to point out a couple of things in the above style:

  1. If I would have used ContentPresenter instead of TextBlock inside the Grid named Chrome, background property was not set on the ContentPresenter and when I snooped (http://snoopwpf.codeplex.com/) the UI, I found that the ContentPresenter has TextBlock whose Background was always set to Default and hence no styletriggers were applied to the TextBlock. Also, this TextBlock's background valuesource is Default.

On the other hand, when I use TextBlock directly inside the Grid named Chrome, I can set its background explicitly to Grid's Background which is set to Button's Background. Snooping reveals that now TextBlock's Background ValueSource is ParentTemplate.

  1. Button picks up MyTextBlockStyle while displaying its content.

  2. Style triggers for Button or TextBlock were never triggered unless I did mouse over the button which changes the button's background to Black and propagates this value down to TextBlock background changing the TextBlock's foreground color to DarkSeaGreen.

  3. Also, changing the button's background in snoop utility while application is running, triggers the Style Triggers.

Questions:

  1. Why none of the Style triggers work for Background property whereas they work for IsMouseOver property?

  2. What I am doing wrong?

  3. Any solution for this?

解决方案

I found the solution to my problem. TextBlock does not derive from Control. Any text shown on UI by any control internally uses TextBlock to represent the textual content. If TextBlock style is set using the following in ResourceDictionary:

<Style TargetType="TextBlock">
    <Setter Property="FontFamily" Value="Arial" />
    <Setter Property="FontSize" Value="12" />
    <Setter Property="FontStyle" Value="Normal" />
</Style>

Any control that represents text will have this style (since no key is assigned to this style which implies that all TextBlock will get it by default) unless the control's template override the TextBlock's default style which can be done as follows:

<Button Grid.Column="1" Style="{StaticResource NoChromeButton}">
    <TextBlock Style="{x:Null}" Text="abc" FontFamily="Segoe UI Symbol"/>
</Button>

This simple setting has resolved most of the issues we have with dynamic foreground color changing.

这篇关于更改前景色动态地根据背景颜色的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆