对于自己做的游戏即使输了脸上一般还是洋溢着笑容的,那么如何做一个简单的游戏呢?示例下载(.netFramework 3.5 SP1)
一.再说呈现
在自绘那篇我们已经知道了如何把东西画出来,或许你已经能通过重载OnRender函数非常熟练的画出这样棋子。
那么OnRender方法中的DrawingContext参数到底来自哪呢?因为DrawingContext是抽象类,所以微软创建了一个叫做RenderDataDrawingContext的具体类以及他的子类VisualDrawingContext,我们的所用的DrawingContext实际就是VisualDrawingContext这个类,不过微软都把他们定义为了internal,我们在程序集以外无法访问,既然无法访问,那么当我们需要多个这样的对象时如何创建呢?
DrawingVisual这类为我们实现多个DrawingContext成为了可能,因为他的实例方法RenderOpen()在内部创建了VisualDrawingContext,DrawingVisual也可以说继承于Visual,当我们用DrawingContext的Drawing一些东西的时候,其实产生的是画图的数据,数据有了,可要把数据给UI 的线程才能被显示,WPF似乎是用ContextLayoutManager这个类来把UI重绘请求放到Dispatcher队列,用Visual里的DUCE发送消息和线程对话.
我们创建可视数据的代码可以写成这样:
DrawingVisual boardVisual = new DrawingVisual(); using (DrawingContext drawingContext = boardVisual.RenderOpen()) { //画棋盘 }
以上是创建了画图的数据,那么怎么用ContextLayoutManager把数据给Dispatcher队列。UIElement中的 PropagateResumeLayout方法循环递归把需要刷新的Visual对象放到队列中,经过这样的分装我们只需要知道把需要呈现的Visual仍给系统就可以,他自己会判断是否要刷新。
怎么给Visual,微软要求我们先给Visual的数量,这需要我们通过以下方式来给定
protected override int VisualChildrenCount { get { return 1; } }
然后他会用一个for循环来得到需要的Visual对象
for (int i = 0; i < internalVisualChildrenCount; i++) { Visual visualChild = v.InternalGetVisualChild(i); if (visualChild != null) { PropagateResumeLayout(v, visualChild); } }
internalVisualChildrenCount的数量就是VisualChildrenCount返回的值, InternalGetVisualChild的方法实际做的就是我们常重载的GetVisualChild方法。
protected override Visual GetVisualChild(int index) { if (index == 0) return boardVisual; else throw new ArgumentOutOfRangeException("out of range"); }
就这么简单,我们是否已经看到自己画的棋盘了。
二.可视树与逻辑树
虽然我也承认这两棵树已经被人刨根问底的掘了N次,但对于自定义控件来说这树可不是说舍弃就舍弃的(要充分合理利用资源嘛)。
逻辑树(Logical Tree)当然是逻辑意义上的,如果把Visual 可以比作汽车的一部分比如车厢,轮胎,油箱,当我们坐在车厢里的时候我们实际也可以说做在车中,车是一个逻辑意义上的含义,是各个汽车零件和的总称。所以我们的控件上的Parent或者是Child一般都是逻辑的物件,那么加入他除了一个标示外,还有其他的什么意义呢?他还可以属性值继承,比如说我们在我们这个象棋控件上设置下字体的变化,希望上面的棋子车、马、帅等的字体也发生变化就可以用到他。
在我们的象棋控件中这样注册:
public static readonly DependencyProperty FontFamilyProperty = DependencyProperty.Register("FontFamily", typeof(FontFamily), typeof(ChineseChessboard), new FrameworkPropertyMetadata(SystemFonts.MessageFontFamily, FrameworkPropertyMetadataOptions.Inherits));
棋子中可以这样
public static readonly DependencyProperty FontFamilyProperty = ChineseChessboard.FontFamilyProperty.AddOwner(typeof(ChessmanControl), new