【问题标题】:Change Class-Binded Shadow Colour WPF更改类绑定阴影颜色 WPF
【发布时间】:2020-09-19 20:38:50
【问题描述】:

我正在研究如何在我的 WPF 文档中复制 Google 按钮的悬停效果阴影,并遇到了这个问题:https://stackoverflow.com/a/53031057/12299798,它准确地回答了我的问题,但我唯一的问题是我通常会做所有的前端XAML 中的东西,所以我对 C# 中的样式不太熟悉。我的问题是我想将我的前景色“绑定”到阴影颜色,这是因为在代码中它只将它设置为灰色,这意味着我必须为我想要的每种颜色做一个完整的其他类设置它。这是我现在的代码:

MainWindow.xaml:

<Button Content="shadow">
        <Button.Style>
            <Style TargetType="Button">
                <Style.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="local:UI.Elevation" Value="10"/>
                    </Trigger>
                    <Trigger Property="IsMouseOver" Value="False">
                        <Setter Property="local:UI.Elevation" Value="0"/>

                    </Trigger>
                </Style.Triggers>
            </Style>
        </Button.Style>
</Button>

UI.cs:

public static class UI
{

    public static readonly DependencyProperty ElevationProperty = DependencyProperty.RegisterAttached("Elevation", typeof(double), typeof(UI), new FrameworkPropertyMetadata(default(double), FrameworkPropertyMetadataOptions.AffectsRender, null, OnRedElevationChanged));

    public static double GetElevation(this UIElement element) => element.GetValue(ElevationProperty) as double? ?? default;

    public static void SetElevation(this UIElement element, double elevation) => element.SetValue(ElevationProperty, elevation);

    private static object OnRedElevationChanged(DependencyObject d, object value)
    {
        if (d is UIElement element && value is double elevation)
            if (elevation == 0)
                element.Effect = null;
            else
            {
                Effect e = CreateElevation(elevation, element.Effect);
                if (e != null)
                    element.Effect = e;
            }
        return value;
    }

    private static Effect CreateElevation(double elevation, Effect source)
    {
        void MixShadows(DropShadowEffect nearest, DropShadowEffect matched, double balance)
        {
            matched.BlurRadius = matched.BlurRadius * (1 - balance) + nearest.BlurRadius * balance;
            matched.ShadowDepth = matched.ShadowDepth * (1 - balance) + nearest.ShadowDepth * balance;
        }
        DropShadowEffect[] shadows = new DropShadowEffect[]
        {
        new DropShadowEffect()
        {
            BlurRadius = 5,
            ShadowDepth = 1
        },
        new DropShadowEffect()
        {
            BlurRadius = 8,
            ShadowDepth = 1.5
        },
        new DropShadowEffect()
        {
            BlurRadius = 14,
            ShadowDepth = 4.5
        },
        new DropShadowEffect()
        {
            BlurRadius = 25,
            ShadowDepth = 8
        },
        new DropShadowEffect()
        {
            BlurRadius = 35,
            ShadowDepth = 13
        }
        };
        elevation = Math.Max(0, elevation / 12 * shadows.Length - 1);
        int prevIndex = (int)Math.Floor(elevation), index = (int)elevation, nextIndex = (int)Math.Ceiling(elevation);
        double approx = elevation - index;
        DropShadowEffect shadow = shadows[index];
        if (approx != 0)
            MixShadows(approx < 0 ? shadows[prevIndex] : shadows[nextIndex], shadow, Math.Abs(approx));
        bool modify = false;
        if (source is DropShadowEffect sourceShadow)
        {
            sourceShadow.BlurRadius = shadow.BlurRadius;
            sourceShadow.ShadowDepth = shadow.ShadowDepth;
            shadow = sourceShadow;
            modify = true;
        }
        shadow.Direction = 270;
        shadow.Color = Colors.Red;
        shadow.Opacity = .42;
        shadow.RenderingBias = RenderingBias.Performance;
        return modify ? null : shadow;
    }
}

为了在 XAML 中得到我想要的,我会做这样的事情:

<Button Content="shadow">
        <Button.Style>
            <Style TargetType="Button">
                <Style.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="local:UI.Elevation" Value="10"/>
                        <Setter Property="local:UI.Elevation.Foreground" Value="Blue"/>
                    </Trigger>
                    <Trigger Property="IsMouseOver" Value="False">
                        <Setter Property="local:UI.Elevation" Value="0"/>
                        <Setter Property="local:UI.Elevation.Foreground" Value="Blue"/>
                    </Trigger>
                </Style.Triggers>
            </Style>
        </Button.Style>
</Button>

但我不太清楚如何链接local:UI.Elevation.Foreground 以更改阴影颜色,我必须在此处从UI.cs 更改此行:shadow.Color = Colors.Red; 并将其绑定到Elevation.Foreground,但是我有困难。有人可以帮忙吗?

【问题讨论】:

    标签: c# wpf binding styling shadow


    【解决方案1】:

    您需要做的就是使用新的附加属性更新 UI 类,该属性名为 Color,类型为 Color,并为其指定您喜欢的默认颜色。

    然后,在其OnColorChanged 处理程序中,调用OnElevationChanged 以便重新创建阴影。

    #region Color (Attached Property)
    public static readonly DependencyProperty ColorProperty =
        DependencyProperty.RegisterAttached(
            "Color",
            typeof(Color),
            typeof(UI),
            new PropertyMetadata(Colors.Black, OnColorChanged));
    
    public static Color GetColor(DependencyObject obj)
    {
        return (Color)obj.GetValue(ColorProperty);
    }
    
    public static void SetColor(DependencyObject obj, Color value)
    {
        obj.SetValue(ColorProperty, value);
    }
    
    private static void OnColorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        OnElevationChanged(d, GetElevation((UIElement)d));
    }
    #endregion
    

    CreateElevation方法中,为颜色添加一个新参数,这样就可以设置了。

    private static Effect CreateElevation(double elevation, Effect source, Color color)
    {
        ...
        shadow.Color = color;
        ...
    }
    

    最后,在OnElevationChanged 中更新它,让它调用GetColor,这样它就可以传入新的Color 属性。

    private static object OnElevationChanged(DependencyObject d, object value)
    {
        if (d is UIElement element && value is double elevation)
            if (elevation == 0)
                element.Effect = null;
            else
            {
                Effect e = CreateElevation(elevation, element.Effect, GetColor(element));
                if (e != null)
                    element.Effect = e;
            }
        return value;
    }
    

    XAML 示例

    <Button
        Width="100"
        Height="20"
        Content="shadow">
        <Button.Style>
            <Style TargetType="Button">
                <Style.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="local:UI.Elevation" Value="10" />
                        <Setter Property="local:UI.Color" Value="Blue" />
                    </Trigger>
                    <Trigger Property="IsMouseOver" Value="False">
                        <Setter Property="local:UI.Elevation" Value="5" />
                        <Setter Property="local:UI.Color" Value="Red" />
                    </Trigger>
                </Style.Triggers>
            </Style>
        </Button.Style>
    </Button>
    

    注意:您可以进行一些重构以使这一切变得更干净,但希望这能让您开始。

    【讨论】:

    • 所以我创建了一个DependencyProperty ColourProperty 和一个OnColourChanged 事件,但我不明白如何将它发送到OnElevationChanged,然后我可以将它发送到CreateElevation跨度>
    • 我用工作代码更新了我的答案。您可能应该花一些时间来了解附加属性的工作原理。这将帮助您更好地理解代码。您可以使用附加的属性/行为做很多事情! :)
    • 效果很好,符合预期!一定会使用 C# 研究附加属性和更多前端设计。再次感谢!
    猜你喜欢
    • 2018-12-02
    • 2019-11-02
    • 1970-01-01
    • 2019-06-30
    • 1970-01-01
    • 2015-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多