zoukankan      html  css  js  c++  java
  • Silverlight学习笔记十四自定义控件之加载时的图形

    这一讲是关于Silverlight的自定义控件的加载图标学习,我做了一个自定义加载。效果图下

    一。首先介绍一下关于Silverlight的自定义控件的步骤以加载图标为例:

     

    步骤1.创建一个DependencyPropertyCloner的静态类用于克隆在界面输入的值,来改变效果。代码如下:

    using System;

    using System.Reflection;
    using System.Windows;

    namespace System.Windons.Control.Extend
    {
        /// <summary>
        /// 克隆注入对象的类型
        /// </summary>
        public static class DependencyPropertyCloner
        {
            /// <summary>
            /// 克隆一个注入对象的类型
            /// </summary>
            /// <typeparam name="T">克隆注入对象的类型</typeparam>
            /// <param name="source">克隆注入对象source</param>
            /// <returns></returns>
            public static T Clone<T>(this T source) where T : DependencyObject
            {
                //用反射创建对象的实例
                T clone = (T)Activator.CreateInstance(source.GetType());

                //克隆对象的注入属性
                CloneAllDependencyProperties<T>(source, clone);

                //克隆对象的所以属性
                CloneAllProperties<T>(source, clone);

                //返回克隆后的对象
                return clone;
            }

            /// <summary>
            /// 克隆注入对象的所有属性
            /// </summary>
            /// <typeparam name="T">克隆注入对象的类型</typeparam>
            /// <param name="source">克隆注入对象source</param>
            /// <param name="clone">克隆后的对象</param>
            private static void CloneAllProperties<T>(T source, T clone) where T : DependencyObject
            {
                Type t = source.GetType();
                //取得对象的属性的数据
                PropertyInfo[] propertyInfos = t.GetProperties();

                foreach (PropertyInfo item in propertyInfos)
                {
                   
                    if (item.Name != "Name" &&
                        item.Name != "Parent" &&
                        item.CanRead && item.CanWrite &&
                        !item.PropertyType.IsArray &&
                        item.GetIndexParameters().Length == 0 &&
                        item.GetValue(source, null) != null)
                    {
                        try
                        {
                            //将item赋值clone
                            item.SetValue(clone, item.GetValue(source, null), null);
                        }
                        catch (TargetInvocationException e)
                        {
                            e.ToString();
                        }

                        catch (MethodAccessException e1)
                        {
                            e1.ToString();
                        }
                    }

                        //从item中获取IList的类型的集合
                    else if (item.PropertyType.GetInterface("IList", true) != null)
                    {
                        //当在派生类中重写时,使用指定的绑定约束并匹配指定的参数列表、修饰符和区域性,调用指定成员。
                        //在item.GetValue(source, null)调用get_Count方法(屏蔽构造器或初始化器)
                        int cnt = (int)item.PropertyType.InvokeMember(
                            "get_Count",
                            BindingFlags.InvokeMethod, null, item.GetValue(source, null), null);
                        for (int i = 0; i < cnt; i++)
                        {
                            object val = item.PropertyType.InvokeMember(
                                "get_Item",
                                BindingFlags.InvokeMethod, null, item.GetValue(source, null), new object[] { i });
                            object nval = val;
                            DependencyObject v = val as DependencyObject;
                            if (v != null)
                            {
                                nval = v.Clone();
                            }
                            try
                            {
                                item.PropertyType.InvokeMember("Add", BindingFlags.InvokeMethod, null, item.GetValue(clone, null), new object[] { nval });

                            }
                            catch (TargetInvocationException e)
                            {
                                e.ToString();
                            }
                        }
                    }
                }
            }

            /// <summary>
            /// 克隆注入对象的注入属性
            /// </summary>
            /// <typeparam name="T">克隆注入对象的类型</typeparam>
            /// <param name="source">克隆注入对象source</param>
            /// <param name="clone">克隆后的对象</param>
            private static void CloneAllDependencyProperties<T>(T source, T clone) where T : DependencyObject
            {
                Type t = source.GetType();
                Type wt = t;

                //如果wt的直接父类不是DependencyObject
                while (wt.BaseType != typeof(DependencyObject))
                {
                    FieldInfo[] fields = wt.GetFields(BindingFlags.Static | BindingFlags.Public);

                    foreach (var fi in fields)
                    {
                        DependencyProperty dp = fi.GetValue(source) as DependencyProperty;
                        if (dp != null && fi.Name != "NameProperty")
                        {
                            DependencyObject obj = source.GetValue(dp) as DependencyObject;
                            if (obj != null)
                            {
                                object o = obj.Clone();
                                clone.SetValue(dp, o);
                            }

                            else
                            {
                                if (fi.Name != "CountProperty" &&
                                         fi.Name != "GeometryTransformProperty" &&
                                         fi.Name != "ActualWidthProperty" &&
                                         fi.Name != "ActualHeightProperty" &&
                                         fi.Name != "MaxWidthProperty" &&
                                         fi.Name != "MaxHeightProperty" &&
                                         fi.Name != "StyleProperty" &&
                                         fi.Name != "TemplateProperty")
                                {
                                    try
                                    {
                                        clone.SetValue(dp, source.GetValue(dp));
                                    }
                                    catch (InvalidOperationException)
                                    {
                                        throw;
                                    }
                                }
                            }
                        }
                    }

                    wt = wt.BaseType;
                }
            }
        }
    }

    步骤2.创建一个LoadingIndicator.cs的控件。代码如下:

    using System;
    using System.Net;
    using System.Windows;
    using System.Windows.Data;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Controls;

    namespace System.Windons.Control.Extend
    {
        /// <summary>
        /// 自定义加载图标控件
        /// </summary>
        [TemplatePart(Name = "PART_AnimationElement", Type = typeof(FrameworkElement))]
        public class LoadingIndicator : System.Windows.Controls.Control
        {
            /// <summary>
            /// 创建实例方法
            /// </summary>
            public LoadingIndicator()
            {
                this.DefaultStyleKey = typeof(LoadingIndicator);
            }

            /// <summary>
            /// 获取半径属性
            /// </summary>
            public static readonly DependencyProperty RadiusProperty =
                DependencyProperty.Register("Radius", typeof(int), typeof(LoadingIndicator),
                new PropertyMetadata(10, new PropertyChangedCallback(ValueChangedCallback)));

            public static readonly DependencyProperty StartOpacityProperty =
                  DependencyProperty.Register("StartOpacity", typeof(double), typeof(LoadingIndicator),
                  new PropertyMetadata(1.0, new PropertyChangedCallback(StartOpacityChangedCallback)));

            public static readonly DependencyProperty EndOpacityProperty =
               DependencyProperty.Register("EndOpacity", typeof(double), typeof(LoadingIndicator),
                new PropertyMetadata(0.1, new PropertyChangedCallback(EndOpacityChangedCallback)));

            public static readonly DependencyProperty DurationProperty =
                DependencyProperty.Register("Duration", typeof(TimeSpan), typeof(LoadingIndicator),
                new PropertyMetadata(TimeSpan.FromSeconds(1), new PropertyChangedCallback(ValueChangedCallback)));

            public static readonly DependencyProperty CountProperty =
                           DependencyProperty.Register("Count", typeof(int), typeof(LoadingIndicator),
                           new PropertyMetadata(12, new PropertyChangedCallback(CountChangedCallback)));

            private static readonly DependencyProperty ControlVisibilityProperty =
                DependencyProperty.Register("ControlVisibility", typeof(Visibility), typeof(LoadingIndicator),
                new PropertyMetadata(Visibility.Visible, new PropertyChangedCallback(ControlVisibilityCallback)));

            /// <summary>
            /// 获取或设置半径
            /// </summary>
            public int Radius
            {
                get { return (int)GetValue(RadiusProperty); }
                set { SetValue(RadiusProperty, value); }
            }

            /// <summary>
            /// 获取或设置开始的透明度值
            /// </summary>
            public double StartOpacity
            {
                get { return (double)GetValue(StartOpacityProperty); }
                set { SetValue(StartOpacityProperty, value); }
            }

            /// <summary>
            /// 获取或设置结束的透明度值
            /// </summary>
            public double EndOpacity
            {
                get { return (double)GetValue(EndOpacityProperty); }
                set { SetValue(EndOpacityProperty, value); }
            }

            /// <summary>
            /// 获取或设置持续的时间
            /// </summary>
            public TimeSpan Duration
            {
                get { return (TimeSpan)GetValue(DurationProperty); }
                set { SetValue(DurationProperty, value); }
            }

            /// <summary>
            /// 元素的个数
            /// </summary>
            public int Count
            {
                get { return (int)GetValue(CountProperty); }
                set { SetValue(CountProperty, value); }
            }

           /// <summary>
            /// 获取或设置控件的可见性
           /// </summary>
            private bool ControlVisibility
            {
                get { return (bool)GetValue(ControlVisibilityProperty); }
                set { SetValue(ControlVisibilityProperty, value); }
            }

            /// <summary>
            /// 获取或设置AnimationElement
            /// </summary>
            private FrameworkElement AnimationElement { get; set; }

            /// <summary>
            /// 获取或设置画布
            /// </summary>
            private Canvas LayoutRoot { get; set; }

            /// <summary>
            /// 在设置的值改变后发生
            /// </summary>
            /// <param name="obj">注入对象</param>
            /// <param name="args">参数</param>
            private static void ValueChangedCallback(DependencyObject obj, DependencyPropertyChangedEventArgs args)
            {
                LoadingIndicator ctl = (LoadingIndicator)obj;
                ctl.CreateAnimation();
            }

            /// <summary>
            /// 设置开始的透明度值改变时发生
            /// </summary>
            /// <param name="obj">注入对象</param>
            /// <param name="args">参数</param>
            private static void StartOpacityChangedCallback(DependencyObject obj, DependencyPropertyChangedEventArgs args)
            {
                LoadingIndicator ctl = (LoadingIndicator)obj;
                ctl.StartOpacity = LoadingIndicator.CorrectOpacityValue((double)args.NewValue);
                ctl.CreateAnimation();
            }

            /// <summary>
            /// 设置结束的透明度值改变时发生
            /// </summary>
            /// <param name="obj">注入对象</param>
            /// <param name="args">参数</param>
            private static void EndOpacityChangedCallback(DependencyObject obj, DependencyPropertyChangedEventArgs args)
            {
                LoadingIndicator ctl = (LoadingIndicator)obj;
                ctl.EndOpacity = LoadingIndicator.CorrectOpacityValue((double)args.NewValue);

                ctl.CreateAnimation();
            }

            /// <summary>
            /// 判断输入的值是否有效
            /// </summary>
            /// <param name="opacity">输入的值</param>
            /// <returns>有效则返回该值</returns>
            private static double CorrectOpacityValue(double opacity)
            {
                if (opacity < 0) return 0;
                if (opacity > 1) return 1;

                return opacity;
            }

            /// <summary>
            /// 元素个数改变时发生
            /// </summary>
            /// <param name="obj">注入对象</param>
            /// <param name="args">参数</param>
            private static void CountChangedCallback(DependencyObject obj, DependencyPropertyChangedEventArgs args)
            {
                LoadingIndicator ctl = (LoadingIndicator)obj;
                int count = (int)args.NewValue;

                //如果所设置的值小于或等于0,则设置为12.默认值
                if (count <= 0)
                {
                    ctl.Count = 12;
                }
                ctl.CreateAnimation();
            }

            /// <summary>
            /// 控件的可见性方法
            /// </summary>
            /// <param name="obj"></param>
            /// <param name="args"></param>
            private static void ControlVisibilityCallback(DependencyObject obj, DependencyPropertyChangedEventArgs args)
            {
                LoadingIndicator ctl = (LoadingIndicator)obj;
                Visibility visibility = (Visibility)args.NewValue;
                if (ctl.LayoutRoot != null)
                {
                    if (visibility == Visibility.Collapsed)
                    {
                        //如果控件不可见,则清除属于该控件的字控件
                        ctl.LayoutRoot.Children.Clear();
                    }

                    else
                    {
                        ctl.CreateAnimation();
                    }
                }
            }

            /// <summary>
            /// 重载OnApplyTemplate方法
            /// </summary>
            public override void OnApplyTemplate()
            {
                base.OnApplyTemplate();
                LayoutRoot = GetTemplateChild("LayoutRoot") as Canvas;
                if (LayoutRoot == null)
                {
                    throw new NotImplementedException("没有可用的LayoutRoot");
                }
                AnimationElement = GetTemplateChild("PART_AnimationElement") as FrameworkElement;
                if (AnimationElement == null)
                {
                    throw new NotImplementedException("Template Part PART_AnimationElement is required to display LoadingIndicator.");
                }
                CreateAnimation();
            }

            /// <summary>
            /// 创建动画方法
            /// </summary>
            private void CreateAnimation()
            {
                if (LayoutRoot != null)
                {
                    LayoutRoot.Children.Clear();
                    double angle = 360.0 / this.Count;
                    double width = AnimationElement.Width;
                    double x = (Width - width) / 2;
                    double y = Height / 2 + Radius;
                    for (int i = 0; i < this.Count; i++)
                    {
                        FrameworkElement element = DependencyPropertyCloner.Clone<FrameworkElement>(AnimationElement);
                        element.Opacity = 0;
                        TranslateTransform tt = new TranslateTransform() { X = x, Y = y };
                        RotateTransform rt = new RotateTransform() { Angle = i * angle + 180, CenterX = (width / 2), CenterY = -Radius };
                        TransformGroup tg = new TransformGroup();
                        tg.Children.Add(rt);
                        tg.Children.Add(tt);
                        element.RenderTransform = tg;
                        LayoutRoot.Children.Add(element);
                        DoubleAnimation animation = new DoubleAnimation();
                        animation.From = this.StartOpacity;
                        animation.From = this.StartOpacity;
                        animation.To = this.EndOpacity;
                        animation.Duration = this.Duration;
                        animation.RepeatBehavior = RepeatBehavior.Forever;
                        animation.BeginTime = TimeSpan.FromMilliseconds((this.Duration.TotalMilliseconds / this.Count) * i);
                        Storyboard.SetTargetProperty(animation, new PropertyPath("Opacity"));
                        Storyboard.SetTarget(animation, element);

                        Storyboard sb = new Storyboard();
                        sb.Children.Add(animation);
                        sb.Begin();
                    }

                    Binding binding = new Binding();
                    binding.Source = this;
                    binding.Path = new PropertyPath("Visibility");
                    this.SetBinding(LoadingIndicator.ControlVisibilityProperty, binding);
                }
            }

        }
    }

    它的默认样式:generic.xaml

    <ResourceDictionary
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:System.Windons.Control.Extend">
        <Style TargetType="local:LoadingIndicator">

            <Setter Property="Template">

                <Setter.Value>

                    <ControlTemplate TargetType="local:LoadingIndicator">

                        <!-- Template's Root Visual -->

                        <Canvas x:Name="LayoutRoot" Background="{TemplateBinding Background}">

                            <Ellipse x:Name="PART_AnimationElement" Width="12" Height="12" Fill="{TemplateBinding Foreground}" />

                        </Canvas>

                    </ControlTemplate>

                </Setter.Value>

            </Setter>

        </Style>

    </ResourceDictionary>

    二。演示

    创建LoadingDemo.xaml文件用于演示效果

    <UserControl xmlns:my="clr-namespace:System.Windons.Control.Extend;assembly=System.Windons.Control.Extend"  x:Class="Silverlight.Common.Other.LoadingDemo"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                
        mc:Ignorable="d"
        d:DesignHeight="300" d:DesignWidth="400">

        <Grid x:Name="LayoutRoot" HorizontalAlignment="Center" VerticalAlignment="Center">
            <Grid.RowDefinitions>
                <RowDefinition Height="auto"/>
                <RowDefinition Height="auto"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="100" />
                <ColumnDefinition Width="100" />
                <ColumnDefinition Width="100" />
                <ColumnDefinition Width="100" />
                <ColumnDefinition Width="100" />
            </Grid.ColumnDefinitions>
            <!--默认图形-->
            <Grid Background="WhiteSmoke" Grid.Column="0">
                <my:LoadingIndicator Width="50" Height="50"  Count="8" Foreground="BlueViolet" x:Name="Indicator1"/>
                <TextBlock Text="加载中..." HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
            </Grid>
            <!--样式一-->
            <Grid Background="#FF124431" Grid.Column="1">
                <Grid.Resources>

                    <Style x:Name="Style1" TargetType="my:LoadingIndicator">

                        <Setter Property="Template">

                            <Setter.Value>

                                <ControlTemplate TargetType="my:LoadingIndicator">
                                    <Canvas x:Name="LayoutRoot" Background="{TemplateBinding Background}">
                                        <Rectangle x:Name="PART_AnimationElement" Width="4" Height="15"
                                                      StrokeThickness="1" Stroke="LightSteelBlue"
                                                RadiusX="1" RadiusY="1" Fill="MidnightBlue" />
                                    </Canvas>

                                </ControlTemplate>

                            </Setter.Value>

                        </Setter>

                    </Style>

                </Grid.Resources>

                <my:LoadingIndicator Width="100" Height="100" Radius="8" Count="24" Duration="0:0:1.5"
                       Style="{StaticResource Style1}" />
            </Grid>

            <!--样式二-->

            <Grid Background="#FFFFECFE" Grid.Column="2">

                <Grid.Resources>

                    <Style x:Name="Style2" TargetType="my:LoadingIndicator">

                        <Setter Property="Template">

                            <Setter.Value>

                                <ControlTemplate TargetType="my:LoadingIndicator">

                                    <Canvas x:Name="LayoutRoot" Background="{TemplateBinding Background}">

                                        <Ellipse x:Name="PART_AnimationElement" Width="16" Height="16" Fill="#FF4C9B18" />
                                    </Canvas>

                                </ControlTemplate>

                            </Setter.Value>

                        </Setter>

                    </Style>

                </Grid.Resources>

                <my:LoadingIndicator Width="100" Height="100" Radius="8" Count="24" Duration="0:0:1.2"
                      Style="{StaticResource Style2}" />
            </Grid>

            <!--样式三-->

            <Grid Background="Black" Grid.Column="3">

                <Grid.Resources>

                    <Style x:Name="Style3" TargetType="my:LoadingIndicator">

                        <Setter Property="Template">

                            <Setter.Value>

                                <ControlTemplate TargetType="my:LoadingIndicator">

                                    <Canvas x:Name="LayoutRoot" Background="{TemplateBinding Background}">


                                        <Ellipse x:Name="PART_AnimationElement" Width="12" Height="12" Fill="White" />
                                    </Canvas>

                                </ControlTemplate>

                            </Setter.Value>

                        </Setter>

                    </Style>

                </Grid.Resources>

                <my:LoadingIndicator  Width="100" Height="100" Style="{StaticResource Style3}" />

            </Grid>

            <!--样式四-->

            <Grid Background="White" Grid.Column="4">

                <Grid.Resources>

                    <Style x:Name="Style4" TargetType="my:LoadingIndicator">

                        <Setter Property="Template">

                            <Setter.Value>

                                <ControlTemplate TargetType="my:LoadingIndicator">

                                    <Canvas x:Name="LayoutRoot" Background="{TemplateBinding Background}">
                                        <Ellipse x:Name="PART_AnimationElement" Width="3" Height="3" Fill="#FF4C9B18" />
                                       
                                    </Canvas>

                                </ControlTemplate>

                            </Setter.Value>

                        </Setter>

                    </Style>

                </Grid.Resources>

                <my:LoadingIndicator  Count="10" Radius="5" Width="40" Height="50"
                      Style="{StaticResource Style4}" />
               
            </Grid>

            <Button x:Name="btnToggleVisibility" Grid.Row="1"  Content="Hide" Click="ToggleVisibility_Click" />
          
        </Grid>
    </UserControl>

     

    后台代码:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;

    namespace Silverlight.Common.Other
    {
        public partial class LoadingDemo : UserControl
        {
            public LoadingDemo()
            {
                InitializeComponent();
            }

            private void ToggleVisibility_Click(object sender, RoutedEventArgs e)
            {
                if (Indicator1.Visibility == System.Windows.Visibility.Collapsed)
                {
                    Indicator1.Visibility = System.Windows.Visibility.Visible;
                    btnToggleVisibility.Content = "Hide";
                }

                else
                {
                    Indicator1.Visibility = System.Windows.Visibility.Collapsed;
                    btnToggleVisibility.Content = "Show";
                }
            }
        }
    }

     

    源代码下载地址:https://files.cnblogs.com/salam/Silverlight.Common.rar

  • 相关阅读:
    [leetcode]259. 3Sum Smaller 三数之和小于目标值
    题型总结之K Sum
    [Leetcode]167. Two Sum II
    题型总结之Sliding Window
    [Leetcode]703. Kth Largest Element in a Stream 数据流中的第 K 大元素
    [Leetcode]307. Range Sum Query
    pycharm同一目录下无法import明明已经存在的.py文件
    python高级特性:迭代器与生成器
    self的含义,为什么类调用方法时需要传参数?
    git三:远程仓库GitHub
  • 原文地址:https://www.cnblogs.com/salam/p/1782925.html
Copyright © 2011-2022 走看看