zoukankan      html  css  js  c++  java
  • .net开发笔记(十二) 设计时与运行时的区别(续)

        上一篇博客详细讲到了设计时(DesignTime)和运行时(RunTime)的概念与区别,不过没有给出实际的Demo,今天整理了一下,做了一个例子,贴出来分享一下,巩固前一篇博客讲到的内容。

        简单回顾一下:

    1. 组件有两种状态,即设计时和运行时,组件存在设计器中时,它就处于“设计时”;组件存在运行过程时,它就处于“运行时”;
    2. 无论设计器中组件还是运行过程中的组件,它们都是“组件实例”,所谓“实例”,就是new出来了对象,可想而知,无论在设计器中还是运行过程中,组件都会执行一些代码;
    3. 一般情况下,可以通过组件的DesignMode是否为true,来判断当前组件是否处于“设计时”。(注意是一般情况);
    4. 之所以分“设计时”和“运行时”两个状态,主要原因是为了照顾微软的“可视化设计”开发模式,因为任何一个组件都有可能存在于设计器中,有些时候,存在于设计器中的组件与运行中的组件有不同的表现行为。详见上一篇博客中最后举得例子。

         为了更为直观地说明“设计时”和“运行时”存在的必要,我做了一个demo,大概描述为:我先设计了一个Ball的控件,它继承自Control,现在我需要让每个Ball受重力的作用,从而能够自由运动,并且能够与容器壁发生碰撞,发生能量损失(速度减小),为了到达这个目的,我从新定义了一个扩展组件(具体含义请参照之前博客),该扩展组件为每个Ball控件扩展出来了一个Gravity属性,当Gravity为true时,Ball就会受重力影响,否则,则不受重力影响。

    先看Ball类代码:

     1 public class Ball : Control
     2     {
     3         public Ball()
     4         {
     5             BackColor = Color.Black;
     6             SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true);
     7         }
     8         protected override void OnResize(EventArgs e)
     9         {
    10             GraphicsPath p = new GraphicsPath();
    11             p.AddEllipse(ClientRectangle);
    12             Region = new Region(p);
    13             base.OnResize(e);
    14         }
    15 }
    View Code

    代码很简单,不做解释。再来看一下扩展组件GravityEngine:

      1  [ProvideProperty("Gravity",typeof(Ball))]
      2     public partial class GravityEngine : Component,IExtenderProvider
      3     {
      4         public GravityEngine()
      5         {
      6             InitializeComponent();
      7         }
      8         public GravityEngine(IContainer container)
      9         {
     10             container.Add(this);
     11             InitializeComponent();
     12         }
     13 
     14         Dictionary<Ball, Info> _dic = new Dictionary<Ball, Info>();
     15         Dictionary<Ball, Point> _dic2 = new Dictionary<Ball, Point>();
     16         float _gravity = 9.8f;
     17         public void SetGravity(Ball ball, bool flag)
     18         {
     19             if (_dic.ContainsKey(ball))
     20             {
     21                 if (!flag)
     22                 {
     23                     _dic.Remove(ball);
     24                 }
     25             }
     26             else
     27             {
     28                 if (flag)
     29                 {
     30                     _dic.Add(ball, new Info());
     31                     ball.MouseDown += new MouseEventHandler(ball_MouseDown);
     32                     ball.MouseUp += new MouseEventHandler(ball_MouseUp);
     33                     ball.MouseMove += new MouseEventHandler(ball_MouseMove);
     34                 }
     35             }
     36         }
     37         public bool GetGravity(Ball ball)
     38         {
     39             if (_dic.ContainsKey(ball))
     40             {
     41                 return true;
     42             }
     43             else
     44             {
     45                 return false;
     46             }
     47         }
     48 
     49         #region IExtenderProvider 成员
     50         public bool CanExtend(object extendee)
     51         {
     52             return extendee is Ball;
     53         }
     54         #endregion
     55 
     56         private void timer1_Tick(object sender, EventArgs e)
     57         {
     58             if (!DesignMode)
     59             {
     60                 foreach (KeyValuePair<Ball, Info> pair in _dic)
     61                 {
     62                     Ball b = pair.Key;
     63                     Info info = pair.Value;
     64                     if (info.Move) //都Gravity影响
     65                     {
     66                         info.YSpeed += _gravity;
     67 
     68                         b.Left += (int)info.XSpeed; //移动水平位置
     69                         b.Top += (int)info.YSpeed;  //移动垂直位置
     70 
     71                         Control parent = b.Parent;
     72                         if (b.Left <= 0) //碰撞左壁
     73                         {
     74                             info.XSpeed = 0.35f * Math.Abs(info.XSpeed); //改变水平速度
     75                             b.Left = 0;
     76                         }
     77                         if (b.Top <= 0) //碰撞上部
     78                         {
     79                             info.YSpeed = 0.95f * Math.Abs(info.YSpeed); //改变垂直速度
     80                             b.Top = 0;
     81                         }
     82                         if (b.Left + b.ClientRectangle.Width >= parent.ClientRectangle.Width) //碰撞右壁
     83                         {
     84                             info.XSpeed = (-1) * 0.35f * Math.Abs(info.XSpeed); //改变水平速度 为负
     85                             b.Left = parent.ClientRectangle.Width - b.ClientRectangle.Width;
     86                         }
     87                         if (b.Top + b.ClientRectangle.Height >= parent.ClientRectangle.Height) //碰撞底部
     88                         {
     89                             info.YSpeed = (-1) * 0.95f * Math.Abs(info.YSpeed); //改变垂直速度 为负
     90                             b.Top = parent.ClientRectangle.Height - b.ClientRectangle.Height;
     91                         }
     92                     }
     93                 }
     94             }
     95         }
     96 
     97         void ball_MouseMove(object sender, MouseEventArgs e)
     98         {
     99             Ball b = sender as Ball;
    100             if (_dic.ContainsKey(b))
    101             {
    102                 if (_dic2.ContainsKey(b)) //
    103                 {
    104                     Point p = b.PointToScreen(e.Location); //将ball坐标系的值 转换屏幕坐标系的值
    105                     Point delta = new Point(p.X - _dic2[b].X, p.Y - _dic2[b].Y);
    106                     b.Location = new Point(b.Location.X + delta.X, b.Location.Y + delta.Y);
    107                     _dic[b].XSpeed = delta.X;
    108                     _dic[b].YSpeed = delta.Y;
    109 
    110                     _dic2[b] = p;
    111                 }
    112             }
    113         }
    114 
    115         void ball_MouseUp(object sender, MouseEventArgs e)
    116         {
    117             Ball b = sender as Ball;
    118             if (_dic.ContainsKey(b))
    119             {
    120                 _dic2.Remove(b);
    121                 _dic[b].Move = true;
    122             }
    123         }
    124 
    125         void ball_MouseDown(object sender, MouseEventArgs e)
    126         {
    127             Ball b = sender as Ball;
    128             if (_dic.ContainsKey(b))
    129             {
    130                 Point _down = b.PointToScreen(e.Location); //将ball的坐标系的值 转换成屏幕坐标系的值
    131                 _dic2.Add(b, _down);
    132                 _dic[b].Move = false; //鼠标选中 不受gravity影响
    133                 _dic[b].XSpeed = 0;
    134                 _dic[b].YSpeed = 0;
    135             }
    136         }
    137 }
    View Code

    正如诸位所见,扩展属性为Gravity,目标位Ball([ProvideProperty("Gravity",typeof(Ball))]),为了存储每个Ball的信息,我还定义了一个Info类,代码如下:

     1  class Info
     2     {
     3         float _xSpeed = 0; //水平速度
     4         float _ySpeed = 0; //垂直速度
     5         bool _move = true; //是否受gravity影响
     6 
     7         public float XSpeed
     8         {
     9             get
    10             {
    11                 return _xSpeed;
    12             }
    13             set
    14             {
    15                 _xSpeed = value;
    16             }
    17         }
    18         public float YSpeed
    19         {
    20             get
    21             {
    22                 return _ySpeed;
    23             }
    24             set
    25             {
    26                 _ySpeed = value;
    27             }
    28         }
    29         public bool Move
    30         {
    31             get
    32             {
    33                 return _move;
    34             }
    35             set
    36             {
    37                 _move = value;
    38             }
    39         }
    40 }
    View Code

    Info类记录每个Ball当前的水平速度、垂直速度以及是否受重力影响(当鼠标选中Ball时,不受重力影响)。

          编译之后,生成一个Ball控件和一个GravityEngine扩展组件,你可以再ToolBox看到。将Ball拖进设计器中的窗体中,然后将GravityEngine拖进设计器,Ball的属性栏就多一个扩展属性“gravityEngine1上的Gravity”,类型为bool。你可以通过设置该属性为true,从而使该Ball受重力作用。编译通过后,界面效果为:

    gif截图效果不太好,所以看着不连贯。如果文章到这儿就完了,那就体现不了本篇博客的任何价值,本文开始就表明本文需要说明“设计时”和“运行时”存在的必要性。

         我们回过头来看一下GravityEngine的代码,其中Timer组件Tick事件处理程序Timer1_Tick中,一开始,就判断了DesignMode的值(if(!DesignMode))也就是说,如果组件(GravityEngine)不处于“设计时”,才开始执行下面的代码(让Ball受重力作用),如果GravityEngine处于“设计时”(也就是存在于设计器中),那么就不会执行下面的代码,是的!这个判断很重要,因为如果没有该判断,无论GravityEngine组件处于设计器中还是实际运行过程中,都会执行Timer1_Tick中那部分代码,这就出现问题了,在你设计的时候,也就是在设计器中,就可以看到Ball受重力作用运动,这个太可怕了,你根本固定不了Ball的位置!我去掉判断,看一下设计器中的截图效果:

    如图,设计器中的Ball控件从矩形中掉下来了。分析主要原因,就是之前讲到的,无论设计器中的组件还是实际运行过程中的组件,都是“组件实例”,都运行了代码,因此,就算在设计器中,Ball也难逃GravityEngine组件的重力控制。

         前几天看见网上有人问读取IO数据的问题,尤其像是串口、Socket通信之类的,需要循环接收外来数据的场合,这些时候最好用到APM(异步编程模型),.net中一般以Begin开头的方法基本都属于该范畴,大多数都是操作IO的,当然也有例外,比如BeginInvoke。很多都属于操作IO,比如上面提到的串口、Socket,还有操作麦克风、摄像头等等,甚至鼠标键盘这些我们不常用到(我指的是不需要我们开发人员直接操作)都是,我找机会整理总结一下,包含很多知识,比如读取数据、判断数据完整性、分析数据、提高底层数据接收效率等等等。

         希望对诸位有帮助。

  • 相关阅读:
    HDU 1102 Constructing Roads
    HDU 1285 确定比赛名次。
    最小生成树 HDU 各种畅通工程的题,prim和kru的模板题
    HDU Jungle Roads 1301 最小生成树、
    并查集小结(转)
    HDU hdu 2094 产生冠军 拓扑排序 判定环
    模运算(转)
    拓扑排序(主要是确定环和加法) HDU 2647 Reward
    HDU 1372 Knight Moves 简单BFS
    用计算机模型浅析人与人之间沟通方式 (一)如何谈话
  • 原文地址:https://www.cnblogs.com/xiaozhi_5638/p/3149967.html
Copyright © 2011-2022 走看看