在Silverlight中,UserControl的继承一直是个麻烦事情,要继承一个View(UserControl或者Page以及其他基类)比在ASP.NET中要麻烦一些。仅仅的在UserControl的类中定义继承会存在各种各样的问题,比如说要修改.g文件;更有不辞辛苦者竟然找到了用后台拼XAML的方式(网上一搜便知),对于有洁癖的程序员,这些解决方案都不是非常理想。
其实从sl3开始,ms就已经告诉我们如何正确的继承UserControl等,只要你新建一个Page(注意,不是UserControl)就能看出端倪。
下面我举个例子(代码截取于我一时兴起做的坦克大战雏形)
using System.Windows; using System.Windows.Controls; namespace EternalTank { public class BaseObject : UserControl { double _x; public double X { get { _x = Canvas.GetLeft(this); return _x; } set { Canvas.SetLeft(this, value); _x = value; } } double _y; public double Y { get { _y = Canvas.GetTop(this); return _y; } set { Canvas.SetTop(this, value); _y = value; } } public ObjectDirection Direction { get; set; } /// <summary> /// 坦克的速度 /// </summary> public double Speed { get { return (double)GetValue(SpeedProperty); } set { SetValue(SpeedProperty, value); } } public static readonly DependencyProperty SpeedProperty = DependencyProperty.Register("Speed", typeof(double), typeof(BaseObject), new PropertyMetadata(10d)); } }
这里代码的意义并不重要,但要记住它是基类并且继承了UserControl,以方便其他的UserControl继承它
namespace EternalTank.Assets { public partial class Brick : BaseObject { public Brick() { InitializeComponent(); } } }
这列的Brick继承了BaseObject,下面才是最关键的一步
<my:BaseObject x:Class="EternalTank.Assets.Brick" xmlns:my="clr-namespace:EternalTank" 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" Background="White"> <Rectangle Fill="Red" Width="13" Height="13"></Rectangle> </Grid> </my:BaseObject>
看出来与一般的UserControl有什么不同了吗?
1.先要在XAML中声明命名空间,对于这个例子则是
xmlns:my="clr-namespace:EternalTank"
2.然后让它作为UserControl的跟元素,大概这个样子
<my:BaseObject>
</my:BaseObject>
运行一下看看,是不是一点问题没有了?
其实就如开篇中提到的一样,这种方法已经广泛的应用于Silverlight中了,比如navigation:Page中,只是鲜有人注意而已。
我个人觉得如果不是特别必要的话应当尽量避免这样的继承,毕竟它也一定程度的增加了我们的工作量和代码理解难度。我的建议是灵活运用MVVM,我们的ViewModel难道不可以有一个共同的基类吗:)