zoukankan      html  css  js  c++  java
  • c#,使用WPF的Adorner实现iPhone上新邮件或消息提示效果实现(二)

    一、背景介绍

        在上一篇《c#,使用WPF的Adorner实现iPhone上新邮件或消息提示效果----实现(一)》中,我们通过PromptableButton,PromptAdorner,PromptChrome实现提示效果,其中PromptableButton提供PromptCount代表提示数量供PromptChrome绑定显示,PromptChrome负责显示提示效果,而PromptAdorner负责呈现PromptChrome。

        但是,这里有个问题,为了要使用PromptAdorner这个装饰件,难道所有的控件都要像PromptableButton控件一样提供PromptCount供装饰件绑定? 如果这样做,如果样装饰一个图片控件,那我们又要继承重写一个?如果直接要在常用控件上直接使用装饰件不就行不通了? 如果不能解决这3个问题,那么耦合度还是太高,通用性也不强。

        基于上面的问题,我们采用依赖属性中另外一个利器--“附加属性”,比如:我们要在Canvas内放置一个按钮并且指定其位置时我们都会写<Button Canvas.Left="100" Canvas.Top="100"/>,这里的Canvas.Left就是附加属性的实际使用。以此参考方法,我们也通过编写附件属性来改进目前的问题。

    二、改进分解说明

        1、改进PromptButton。

        该自定义按钮内不再拥有PromptCount属性,因为我们要把依赖属性挪挪地方了。

    View Code
        internal class PromptableButton : Button {
    
            public ImageSource CoverImageSource {
                get { return (ImageSource)GetValue(CoverImageSourceProperty); }
                set { SetValue(CoverImageSourceProperty, value); }
            }
    
            public static readonly DependencyProperty CoverImageSourceProperty =
                DependencyProperty.Register("CoverImageSource", typeof(ImageSource), typeof(PromptableButton), new UIPropertyMetadata(null));
    
    
            public PromptableButton() {
                
            }
            
            static PromptableButton() {
                DefaultStyleKeyProperty.OverrideMetadata(typeof(PromptableButton), new FrameworkPropertyMetadata(typeof(PromptableButton)));
            }
        }

        2、改进PromptAdorner。

        我们需要两个依赖属性:IsPromptEnabled,PromptCount。

        IsPromptEnabled用来控制装饰件是否可用,PromptCount从PromptButton处挪过来。

        这两个依赖属性的定义时,使用DependencyProperty.RegisterAttached方法注册,说明这是附加属性,并且采用两个静态方法(Get/Set)作为附加属性的访问器。

    public static readonly DependencyProperty PromptCountProperty =
                DependencyProperty.RegisterAttached("PromptCount", typeof(int), typeof(PromptAdorner),
                new FrameworkPropertyMetadata(0, new PropertyChangedCallback(PromptCountChangedCallBack), new CoerceValueCallback(CoercePromptCountCallback)));
    
            public static int GetPromptCount(DependencyObject obj) {
                return (int)obj.GetValue(PromptCountProperty);
            }
    
            public static void SetPromptCount(DependencyObject obj, int value) {
                obj.SetValue(PromptCountProperty, value);
            }
    
    
            public static readonly DependencyProperty IsPromptEnabledProperty =
                DependencyProperty.RegisterAttached("IsPromptEnabled", typeof(bool), typeof(PromptAdorner),
                new FrameworkPropertyMetadata(false, new PropertyChangedCallback(IsPromptEnabledChangedCallBack), null));
    
            public static bool GetIsPromptEnabled(DependencyObject obj) {
                return (bool)obj.GetValue(IsPromptEnabledProperty);
            }
    
            public static void SetIsPromptEnabled(DependencyObject obj, bool value) {
                obj.SetValue(IsPromptEnabledProperty, value);
            }
    

        接下来我们在IsPromptEnabledChangedCallBack方法中实现装饰件的创建和移除,该方法会在IsPromptEnabled属性变化时调用:

            public static void IsPromptEnabledChangedCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e) {
                var source = d as FrameworkElement;
    
                bool isEnabled = (bool)e.NewValue;
                if (isEnabled) {
                    //装饰件可用,添加装饰件
    
                    AdornerLayer layer = AdornerLayer.GetAdornerLayer(source);
                    if (layer != null) {
                        //能够获取装饰层,说明已经load过了,直接生成装饰件
                        var adorner = new PromptAdorner(source);
                        layer.Add(adorner);
                    }
                    else {
                        //layer为null,说明还未load过(整个可视化树中没有装饰层的情况不考虑)
                        //在控件的loaded事件内生成装饰件
                        source.Loaded += (s1, e1) => {
                            var adorner = new PromptAdorner(source);
                            AdornerLayer.GetAdornerLayer(source).Add(adorner);
                        };
                    }
                }
                else {
                    //装饰件不可用,移除装饰件
                    AdornerLayer layer = AdornerLayer.GetAdornerLayer(source);
                    if (layer != null) {
                        Adorner[] AllAdorners = layer.GetAdorners(source);
                        if (AllAdorners != null) {
                            IEnumerable<Adorner> desAdorners = AllAdorners.Where(p => p is PromptAdorner);
                            if (desAdorners != null && desAdorners.Count() > 0) {
                                desAdorners.ToList().ForEach(p => layer.Remove(p));
                            }
                        }
                    }
                }
            }

        3、PromtpChrome的改进。

        主要修改该自定义控件描述皮肤的XAML中,对PromptCount的绑定写法。

        这里的绑定使用了附加属性绑定的写法,列如:

    <Label Content="{Binding Path=(local:PromptAdorner.PromptCount)}" .... />

        <Style TargetType="{x:Type local:PromptChrome}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type local:PromptChrome}">
                        <Grid x:Name="container">
                            <!--最外圈的白色圆框,并对其作阴影效果-->
                            <Ellipse Fill="White">
                                <Ellipse.Effect>
                                    <DropShadowEffect BlurRadius="6" 
                                                      ShadowDepth="6" 
                                                      Opacity="0.8"
                                                      Direction="270" 
                                                      RenderingBias="Performance"/>
                                </Ellipse.Effect>
                            </Ellipse>
                            
                            <!--内部的上半圆-->
                            <Ellipse Margin="3">
                                <Ellipse.Fill>
                                    <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                                        <GradientStop Offset="0" Color="#FFF4AEB1"/>
                                        <GradientStop Offset="0.5" Color="#FFE3313A"/>
                                        <GradientStop Offset="1" Color="#FFE3313A"/>
                                    </LinearGradientBrush>
                                </Ellipse.Fill>
                            </Ellipse>
    
                            <!--内部的下半圆,通过采用Exclude模式合并上下两个圆来完成-->
                            <Path  HorizontalAlignment="Center" VerticalAlignment="Center">
                                <Path.Data>
                                    <CombinedGeometry GeometryCombineMode="Exclude" >
                                        <CombinedGeometry.Geometry1>
                                            <EllipseGeometry Center="14 14"  RadiusX="14" RadiusY="14" />
                                        </CombinedGeometry.Geometry1>
                                        
                                        <CombinedGeometry.Geometry2>
                                            <EllipseGeometry Center="14 0"  RadiusX="18" RadiusY="14"/>
                                        </CombinedGeometry.Geometry2>
                                    </CombinedGeometry>
                                </Path.Data>
                                
                                <Path.Fill>
                                    <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                                        <GradientStop Offset="0" Color="#FFDF151F"/>
                                        <GradientStop Offset="1" Color="#FFBA0004"/>
                                    </LinearGradientBrush>
                                </Path.Fill>
                            </Path>
                            
                            <Viewbox Stretch="Uniform" >
                                <!--绑定上文中的PromptCount属性-->
                                <Label Content="{Binding Path=(local:PromptAdorner.PromptCount)}" 
                                       x:Name="label"
                                       Foreground="White"
                                       FontWeight="Bold"
                                       FontSize="14"
                                       HorizontalAlignment="Center"
                                       VerticalAlignment="Center"/>
                            </Viewbox>
                        </Grid>
                        
                        <ControlTemplate.Triggers>
                            <!--使用数据触发器,当PromptCount为0时,隐藏提示-->
                            <DataTrigger Binding="{Binding Path=(local:PromptAdorner.PromptCount)}" Value="0">
                                <Setter TargetName="container" Property="Visibility" Value="Hidden"/>
                            </DataTrigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

    三、使用

        在原先PromptableButton的XAML代码使用处,我们增加了两个依赖属性用来控制和显示装饰件。

    <local:PromptableButton x:Name="button1" Grid.Row="1" CoverImageSource="001.png" Width="128" Height="128" 
                                    local:PromptAdorner.IsPromptEnabled="True"
                                    local:PromptAdorner.PromptCount="0"/>

       我们也可以直接在一个常用控件上使用带提示效果的装饰件。

    <Button x:Name="button2" Grid.Row="4" Width="150" Height="60" Content="按钮2" 
                                   local:PromptAdorner.IsPromptEnabled="True"
     
                                   local:PromptAdorner.PromptCount
    ="1"//>

        至此,改进完成,改进后的装饰件已具备松耦合,通用性的能力。

        其余内容详见源代码。

    四、代码

    http://download.csdn.net/download/kongxh_1981/9161579

  • 相关阅读:
    Haskell Interactive Development in Emacs
    Access Java API in Groovy Script
    手工设置Eclipse文本编辑器的配色
    Color Theme of Emacs
    Gnucash的投资记录
    Special Forms and Syntax Sugars in Clojure
    Use w3m as Web Browser
    SSE指令集加速之 I420转BGR24
    【图像处理】 增加程序速度的方法
    TBB 入门笔记
  • 原文地址:https://www.cnblogs.com/kongxianghai/p/2593357.html
Copyright © 2011-2022 走看看