一步一步创建自定义silverlight控件

         注册了博客没有写一篇文章,浪费了空间。今天刚好跟同事聊到了silverlight 的控件自定义,写一篇 silverlight 2.0的也算是对以前的复习。

         这个例子本身很简单,实现的是简单的带有动画的按钮,主要是谈谈其实现手法。其可分为几点一步一步实现:

1:创建一个silverlight 类库项目,我们将这个项目命名为:TestControl。然后在该项目下添加一个文件夹取名为“themes”,继续在文件下添加一个文本文件“generic.xaml”注意后缀名也修改了(具体为什么做下面说明)。大概样子如图:

        

接着该讨论这个控件的样式了,打开“generic.xaml”文件,默认是空白的,我们将在这边定义样式,先引入内嵌样式,导入命名空间:

         <ResourceDictionary

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml>

</ResourceDictionary>

完成这个步骤以后,在项目中添加一个类“TestControl.cs”,开发一个控件我们就要选择基类继承过来,这边选择的是Control,当然也可以从其他类继承具体是:

         public class TestControl : Control

    {

        public TestControl()

        {

            this.DefaultStyleKey = typeof(TestControl);

        }

 }

这边添加了一个构造函数,在这边的作用是对默认样式的引用,上面我们提到了建立“themes”文件夹,.net会默认的从这个文件夹下面加载generic.xaml 作为控件的默认样式,这下清楚了(创建默认文件名称)吧。让我们继续添加样式吧,打开generic.xaml文件,把控件命名空间引用进来xmlns:local="clr-namespace:TestControl" 我把控件的引用命名为local,当然这边你可以根据自己的喜爱来命名这个。接下来就添加样式:

<Style TargetType="local:TestControl">

        <Setter Property="Template">

            <Setter.Value>

                <ControlTemplate TargetType="local:TestControl">

                    <Grid x:Name="RootElement" Height="{TemplateBinding Height}" Width="{TemplateBinding Width}" Margin="0,0,0,0">

                        <Rectangle x:Name="bevelEllipse" Opacity="1" RadiusX="5" RadiusY="5">

                            <Rectangle.Fill>

                                <ImageBrush x:Name="ImageBrush1"></ImageBrush>

                            </Rectangle.Fill>

                            <Rectangle.Triggers>

                                <EventTrigger>

                                    <BeginStoryboard>

                                        <Storyboard>

                                            <DoubleAnimation Storyboard.TargetName="bevelEllipse" Storyboard.TargetProperty="(Rectangle.Opacity)" From="1" To="0" RepeatBehavior="Forever"></DoubleAnimation>

                                        </Storyboard>

                                    </BeginStoryboard>

                                </EventTrigger>

                            </Rectangle.Triggers>

                        </Rectangle>

                    </Grid>

                </ControlTemplate>

            </Setter.Value>

        </Setter>

    </Style>

 

这边如果有不解的可以去查看帮助文档,讲述的很详细。

这边矩形使用了一个图片的画刷,但是我们没有定义图片路径,这边就是接下来就说的在silverlight自定义属性,这个属性的定义可能有别与我们平时的属性定义,可以说有点复杂。在谈这个之前先说明一个特性 TemplatePart 这个我们可以理解为我们定义一个复合控件,我们把控件分成很多部分,然而TemplatePart 就是用于描述每一个部分的定义。我这边只是为了简单的说所以控件我分成了两块,引用的代码:

[TemplatePart(Name = "bevelEllipse", Type = typeof(Rectangle))]

    [TemplatePart(Name = "ImageBrush1", Type = typeof(ImageBrush))]

    public class TestControl : Control

 

对这个特性有熟悉了,就可以继续定义属性这边具体就不多说了直接放上代码一看便知:

#region 定义属性

        public static readonly DependencyProperty ImagePathProperty;

 

        static TestControl()

        {

            ImagePathProperty = DependencyProperty.Register("ImagePath", typeof(ImageSource), typeof(TestControl),

                new PropertyMetadata(null, new PropertyChangedCallback(TestControl.OnImagePropertyChanged)));

        }

 

        void OnImagePropertyChanged(DependencyPropertyChangedEventArgs e)

        {

            try

            {

                (GetTemplateChild("ImageBrush1") as ImageBrush).ImageSource = e.NewValue as ImageSource;

            }

            catch

            { }

        }

 

        private static void OnImagePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)

        {

            (d as TestControl).OnImagePropertyChanged(e);

        }

 

        public ImageSource ImagePath

        {

            get { return (ImageSource)base.GetValue(ImagePathProperty); }

            set { base.SetValue(ImagePathProperty, value); }

        }

 

        #endregion

 

这边定义了静态构造函数,进行赋值,还有就是DependencyProperty.Register("ImagePath", typeof(ImageSource), typeof(TestControl)  

这边的ImagePath 要和我们定义的属性名称一致,还有注册的类型对应。这样就定义了一个属性。

下面谈谈控件里面的事件是如果定义的,先说明这边跟自定义webControl 的事件处理是一样的方式,好了具体的描述一下:

    定义一个参数的类型,都是从EventArgs 继承,代码如下:

public class TestEventArges : EventArgs

    {

        private Guid _guid;

 

        public Guid TheGuid

        {

            get { return _guid; }

        }

 

        public TestEventArges(Guid guid)

        {

            this._guid = guid;

        }

}

这边我们定义了一个Guid类型作为事件参数,定义这个其实没有什么实际的作用,只是为了测试我们定义的事件。

接下来我们声明委托:

public delegate void TestEventHander(object sender,TestEventArges e);

声明一个TestEventHander 的委托,用于自定义事件。

 

看看控件的事件定义:

#region 定义事件

        public event TestEventHander TestEvented;

 

        protected virtual void OnTestEvented(TestEventArges e)

        {

            if (TestEvented != null)

            {

                TestEvented(this, e);

            }

        }

        #endregion

接着要做的事情就是把控件的事件,关联到触发事件上面,看看下面代码:

private Rectangle _clickEllipse;

        private ImageBrush _imageBrush;

        public TestControl()

        {

            this.DefaultStyleKey = typeof(TestControl);

        }

 

        public override void OnApplyTemplate()

        {

            base.OnApplyTemplate();

 

            _imageBrush = GetTemplateChild("ImageBrush1") as ImageBrush;

            _imageBrush.ImageSource = this.ImagePath;

            //添加Ellipse 引用

            _clickEllipse = GetTemplateChild("bevelEllipse") as Rectangle;

            _clickEllipse.MouseLeftButtonDown += new MouseButtonEventHandler(_clickEllipse_MouseLeftButtonDown);

        }

 

        void _clickEllipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)

        {

            Guid guid = Guid.NewGuid();

            TestEventArges amyE = new TestEventArges(guid);

            OnTestEvented(amyE);

        }

这边重写基类的OnAppleTemplat()方法,这里面 声明了一个Rectangle 和ImageBrouh,对他们的引用是通过GetTemplateChild 方法,方法的参数是跟类的Templat特性定义的名称一样的,关联到样式里面的X:Name 名称的。

_clickEllipse = GetTemplateChild("bevelEllipse") as Rectangle;

            _clickEllipse.MouseLeftButtonDown += new MouseButtonEventHandler(_clickEllipse_MouseLeftButtonDown);

        }

 

        void _clickEllipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)

        {

            Guid guid = Guid.NewGuid();

            TestEventArges amyE = new TestEventArges(guid);

            OnTestEvented(amyE);

        }

取得Rectangle 的定义,定义出这个矩形的鼠标的事件,使用鼠标事件去触发我们自定义的事件,参数里面传入了一个Guid 。好的基本上这个控件算是完成了,下面是完全的代码:

1:样式:

<ResourceDictionary

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:local="clr-namespace:TestControl">

    <Style TargetType="local:TestControl">

        <Setter Property="Template">

            <Setter.Value>

                <ControlTemplate TargetType="local:TestControl">

                    <Grid x:Name="RootElement" Height="{TemplateBinding Height}" Width="{TemplateBinding Width}" Margin="0,0,0,0">

                        <Rectangle x:Name="bevelEllipse" Opacity="1" RadiusX="5" RadiusY="5">

                            <Rectangle.Fill>

                                <ImageBrush x:Name="ImageBrush1"></ImageBrush>

                            </Rectangle.Fill>

                            <Rectangle.Triggers>

                                <EventTrigger>

                                    <BeginStoryboard>

                                        <Storyboard>

                                            <DoubleAnimation Storyboard.TargetName="bevelEllipse" Storyboard.TargetProperty="(Rectangle.Opacity)" From="1" To="0" RepeatBehavior="Forever"></DoubleAnimation>

                                        </Storyboard>

                                    </BeginStoryboard>

                                </EventTrigger>

                            </Rectangle.Triggers>

                        </Rectangle>

                    </Grid>

                </ControlTemplate>

            </Setter.Value>

        </Setter>

    </Style>

</ResourceDictionary>

 

2:后台定义

[TemplatePart(Name = "bevelEllipse", Type = typeof(Rectangle))]

    [TemplatePart(Name = "ImageBrush1", Type = typeof(ImageBrush))]

    public class TestControl : Control

    {

        #region 定义属性

        public static readonly DependencyProperty ImagePathProperty;

 

        static TestControl()

        {

            ImagePathProperty = DependencyProperty.Register("ImagePath", typeof(ImageSource), typeof(TestControl),

                new PropertyMetadata(null, new PropertyChangedCallback(TestControl.OnImagePropertyChanged)));

        }

 

        void OnImagePropertyChanged(DependencyPropertyChangedEventArgs e)

        {

            try

            {

                (GetTemplateChild("ImageBrush1") as ImageBrush).ImageSource = e.NewValue as ImageSource;

            }

            catch

            { }

        }

 

        private static void OnImagePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)

        {

            (d as TestControl).OnImagePropertyChanged(e);

        }

 

        public ImageSource ImagePath

        {

            get { return (ImageSource)base.GetValue(ImagePathProperty); }

            set { base.SetValue(ImagePathProperty, value); }

        }

 

        #endregion

 

        private Rectangle _clickEllipse;

        private ImageBrush _imageBrush;

        public TestControl()

        {

            this.DefaultStyleKey = typeof(TestControl);

        }

 

        public override void OnApplyTemplate()

        {

            base.OnApplyTemplate();

 

            _imageBrush = GetTemplateChild("ImageBrush1") as ImageBrush;

            _imageBrush.ImageSource = this.ImagePath;

            //添加Ellipse 引用

            _clickEllipse = GetTemplateChild("bevelEllipse") as Rectangle;

            _clickEllipse.MouseLeftButtonDown += new MouseButtonEventHandler(_clickEllipse_MouseLeftButtonDown);

        }

 

        void _clickEllipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)

        {

            Guid guid = Guid.NewGuid();

            TestEventArges amyE = new TestEventArges(guid);

            OnTestEvented(amyE);

        }

 

        #region 定义事件

        public event TestEventHander TestEvented;

 

        protected virtual void OnTestEvented(TestEventArges e)

        {

            if (TestEvented != null)

            {

                TestEvented(this, e);

            }

        }

        #endregion

    }

 

public delegate void TestEventHander(object sender,TestEventArges e);

接下来就是测试我们的控件了,添加一个silverlight 应用程序 TestTimeClock ,然后添加项目引用。在默认的Page.xaml 添加如下测试代码:

<UserControl x:Class="TestTimeClock.page"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:myContron="clr-namespace:TestControl;assembly=TestControl">

    <Grid x:Name="LayoutRoot">

        <myContron:TestControl Width="400" Height="300" ImagePath="tu.jpg" TestEvented="TestControl_TestEvented">

        </myContron:TestControl>

    </Grid>

 

</UserControl>

后台代码:

public partial class Page : UserControl

    {

        public Page()

        {

            InitializeComponent();

        }

 

        private void TestControl_TestEvented(object sender, TestControl.TestEventArges e)

        {

            MessageBox.Show("控件的Guid是:" + e.TheGuid);

        }

 

    }

运行就可以看到效果了:

可以比较每次的输出Guid都不相同。

转载于:https://www.cnblogs.com/kuku-zhang/archive/2009/03/15/1412164.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值