更新使用静态属性的元素的可视化

时间:2016-02-29 18:33:04

标签: c# wpf data-binding datatemplate

我使用SystemParameters.WindowGlassColor来更改一堆Foreground的{​​{1}},但是wpf无法检测到该静态值的颜色变化。

TabItems

转换器检测颜色是否更暗或更亮并返回反转的亮度画笔。此外,如果W10机器的设置<Setter Property="Foreground" Value="{Binding Source={x:Static SystemParameters.WindowGlassColor}, Converter={StaticResource WindowColorToForegroundConverter}}"/> 已关闭(通过注册表)。

我可以通过Show Color on Start, Taskbar, Action Center检测颜色何时发生变化,但我无法更新SystemParameters.StaticPropertyChanged

如何让我的应用知道窗口颜色的变化?

如何更新Foreground的视觉效果?

1 个答案:

答案 0 :(得分:1)

我已经成功了!

我的目标是根据当前窗口标题/ Chrome颜色更新TabItems的样式,但由于Static属性未触发Triggers,我必须通过代码来做到这一点。

由于我的应用可以将Chrome扩展到客户端区域,因此当窗口颜色较暗时,某些Labels可能难以阅读。

这是我工作的结果:

灯: Light Theme

黑暗: Dark Theme

以下是:

我使用StaticPropertyChanged

检测窗口颜色的变化
private void SystemParameters_StaticPropertyChanged(object sender, PropertyChangedEventArgs e)
{
    if (e.PropertyName == "WindowGlassColor")
    {
        RibbonTabControl.UpdateVisual();
    }
}

我必须使用名为TabItem的单个布尔属性创建自定义IsDark控件。

我的TabControl有一个更新IsDark值的公共方法:

public void UpdateVisual()
{
    //If glass isn't enabled, ignore.
    var isDark = !SystemParameters.IsGlassEnabled 
           //Gets a registry value. See below.
        || !Glass.UsesColor 
           //Color threshold. See below.   
        || SystemParameters.WindowGlassColor.GetBrightness() < 137; 

    //Manually update the IsDark property.
    foreach (var tab in _tabPanel.Children.OfType<AwareTabItem>())
    {
        tab.IsDark = isDark;
    }
}

获取是否已选中Show Color on Start, Taskbar, Action Center

public static bool UsesColor
{
    get
    {
        try
        {
            //Start menu: 
            //HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\
            //CurrentVersion\Themes\Personalize
            var autoColorization = 
                Registry.GetValue(@"HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\DWM", 
                    "ColorPrevalence", "0").ToString();

            return autoColorization.Equals("1");
        }
        catch (Exception)
        {
            return false;
        }
    }
}

获取给定Color的亮度值:

public static int GetBrightness(this Color c)
{
    //I discovered that 137 is the threshold, if more than that,
    //the window title is white. Less than that, is black.
    return (int)Math.Sqrt(
        c.R * c.R * .241 +
        c.G * c.G * .691 +
        c.B * c.B * .068);
}

最后,我的AwareTabItem Style

<Style TargetType="{x:Type local:AwareTabItem}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:AwareTabItem}">
                <Grid Name="Panel" Background="Transparent">
                    <Border Name="ContentBorder" BorderBrush="#FFD4D4D4" BorderThickness="0">
                        <ContentPresenter x:Name="ContentSite"
                                          VerticalAlignment="Center" Effect="{x:Null}"
                                          HorizontalAlignment="Center"
                                          ContentSource="Header" Margin="10,2"/>
                    </Border>
                </Grid>

                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="True" SourceName="Panel">
                        <Setter Property="Foreground" Value="#FF2B579A" />
                        <Setter Property="Background" Value="#FFFAFAFA" />
                    </Trigger>

                    <Trigger Property="IsSelected" Value="True">
                        <Setter TargetName="Panel" Property="Background" Value="#FFFAFAFA" />
                        <Setter Property="Foreground" Value="#FF2B579A" />
                        <Setter TargetName="ContentBorder" Property="BorderThickness" Value="1,1,1,0" />
                    </Trigger>

                    <!--When ExtendChrome, !IsDark, !IsSelected-->
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition Binding="{Binding Source={x:Static prop:Settings.Default}, Path=EditorExtendChrome, FallbackValue=False}" Value="True"/>
                            <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsDark}" Value="False"/>
                            <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsSelect}" Value="False"/>
                        </MultiDataTrigger.Conditions>

                        <Setter Property="Foreground" Value="#FF000000"/>

                        <Setter TargetName="ContentBorder" Property="Background">
                            <Setter.Value>
                                <RadialGradientBrush>
                                    <GradientStop Color="#9AFFFFFF" Offset="0"/>
                                    <GradientStop Color="#90FFFFFF" Offset="0.4"/>
                                    <GradientStop Offset="1"/>
                                </RadialGradientBrush>
                            </Setter.Value>
                        </Setter>
                    </MultiDataTrigger>

                    <!--When ExtendChrome, !IsDark, IsMouseOver-->
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition Binding="{Binding Source={x:Static prop:Settings.Default}, Path=EditorExtendChrome, FallbackValue=False}" Value="True"/>
                            <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsDark}" Value="False"/>
                            <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}" Value="True"/>
                        </MultiDataTrigger.Conditions>

                        <Setter Property="Foreground" Value="#FF2B579A"/>
                    </MultiDataTrigger>

                    <!--When ExtendChrome, !IsDark, IsSelected-->
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition Binding="{Binding Source={x:Static prop:Settings.Default}, Path=EditorExtendChrome, FallbackValue=False}" Value="True"/>
                            <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsDark}" Value="False"/>
                            <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsSelected}" Value="True"/>
                        </MultiDataTrigger.Conditions>

                        <Setter TargetName="Panel" Property="Background" Value="#FFFAFAFA" />
                        <Setter Property="Foreground" Value="#FF2B579A" />
                        <Setter TargetName="ContentBorder" Property="BorderThickness" Value="1,1,1,0" />
                    </MultiDataTrigger>

                    <!--When ExtendChrome, IsDark, !IsSelected-->
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition Binding="{Binding Source={x:Static prop:Settings.Default}, Path=EditorExtendChrome, FallbackValue=False}" Value="True"/>
                            <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsDark}" Value="True"/>
                            <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsSelected}" Value="False"/>
                        </MultiDataTrigger.Conditions>

                        <Setter Property="Foreground" Value="#FFF8F8FF"/>

                        <Setter TargetName="ContentBorder" Property="Background">
                            <Setter.Value>
                                <RadialGradientBrush>
                                    <GradientStop Color="{Binding Source={x:Static SystemParameters.WindowGlassColor}, 
                                                  Converter={StaticResource ColorToAlphaConverter}, ConverterParameter=6E}" Offset="0"/>
                                    <GradientStop Color="{Binding Source={x:Static SystemParameters.WindowGlassColor}, 
                                                  Converter={StaticResource ColorToAlphaConverter}, ConverterParameter=50}" Offset="0.4"/>
                                    <GradientStop Offset="1"/>
                                </RadialGradientBrush>
                            </Setter.Value>
                        </Setter>
                    </MultiDataTrigger>

                    <!--When ExtendChrome, IsDark, IsMouseOver-->
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition Binding="{Binding Source={x:Static prop:Settings.Default}, Path=EditorExtendChrome, FallbackValue=False}" Value="True"/>
                            <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsDark}" Value="True"/>
                            <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}" Value="True"/>
                        </MultiDataTrigger.Conditions>

                        <Setter Property="Foreground" Value="#FFBFEFFF"/>
                    </MultiDataTrigger>

                    <!--When ExtendChrome, IsDark, IsSelected-->
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition Binding="{Binding Source={x:Static prop:Settings.Default}, Path=EditorExtendChrome, FallbackValue=False}" Value="True"/>
                            <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsDark}" Value="True"/>
                            <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsSelected}" Value="True"/>
                        </MultiDataTrigger.Conditions>

                        <Setter TargetName="Panel" Property="Background" Value="#FFFAFAFA" />
                        <Setter Property="Foreground" Value="#FF2B579A" />
                        <Setter TargetName="ContentBorder" Property="BorderThickness" Value="1,1,1,0" />
                    </MultiDataTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>

    <!--Default Values-->
    <Setter Property="FontFamily" Value="Segoe UI Semilight"/>
</Style>

我注意到当使用深色窗口颜色时,黑色RadialGradientBrush产生了奇怪的效果,所以我使用实际的窗口颜色来制作柔和的背景(以提高可读性窗户太透明了)。要使用GradientStop,我必须创建一个Converter,它采用当前窗口颜色并将给定参数应用为alpha值。

ColorToAlpha转换器:

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
    var color = value as Color?;
    var alphaAux = parameter as string;

    if (!color.HasValue)
        return value;

    if (String.IsNullOrEmpty(alphaAux))
        return value;

    int alpha = 0;
    if (!int.TryParse(alphaAux, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out alpha))
        return value;

    return Color.FromArgb((byte)alpha, color.Value.R, color.Value.G, color.Value.B);
}