WPF自定义控件 —— 复合控件(中国象棋联机版)

本文介绍了如何使用WPF开发一款中国象棋的联机版游戏,包括控件的自定义、事件处理、动画效果、联机操作等关键步骤。通过讲解可视树与逻辑树、HitTest和TranslateTransform,以及动画提醒等功能,展示了WPF自定义控件的强大能力。
摘要由CSDN通过智能技术生成

<script type="text/JavaScript"> </script> <script src="http://a.alimama.cn/inf.js" type="text/javascript"></script>

对于自己做的游戏即使输了脸上一般还是洋溢着笑容的,那么如何做一个简单的游戏呢?示例下载(.netFramework 3.5 SP1)

 image

image

一.再说呈现

在自绘那篇我们已经知道了如何把东西画出来,或许你已经能通过重载OnRender函数非常熟练的画出这样棋子。

image

那么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(
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
WPF 国际象棋 棋子ChessProgrammingTest.zip 要求: You have been provided with a third-party library "ChessLib" which calculates the legal moves a knight can make given a position on an 8 by 8 board. The library has been used to create a program which moves a knight randomly around a board, given an initial starting position and a total number of moves to make. Problem: ======== Extend this program to set up an 8 by 8 square game board containing several different pieces in predefined positions. For each move of the game, the program will choose a piece at random, and move it to a randomly selected valid position. You are not allowed to change any of the ChessLib code. Extend the program as required. Use Object Oriented Design and Modeling appropriately for extensibility. Please supply all the code for your solution in the file Answer.cs in the SampleProgram project. Please supply all the tests for your solution in the file TestAnswer.cs in the SampleProgram.Test project. Game Rules: ----------- * Only one piece can occupy any position on the board at a given time. * All pieces can “jump” any occupied position. Note: Although the game bears a striking resemblance to Chess, this is entirely coincidental. Do not assume other chess rules apply. Game Pieces to support: ----------------------- * Knight – Moves as implemented by ChessLib * Bishop - Moves diagonally, any distance within board boundaries * Queen – Moves diagonally, horizontally or vertically, any distance within board boundaries
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值