.Net Micro Framework研究—应用实例

简介: 在前几篇关于.Net Micro Framework的研究文章中,我对它的绘图功能实不敢恭维,不过微软的MF开发人员很聪明,对位图方面的功能实现的就比较完善,这样做起图形应用来就不至于捉襟见肘了。前段时间用.Net Compact Framework实现了一个奥运场馆查询

试验平台:.Net Micro Framework 模拟器
在前几篇关于.Net Micro Framework的研究文章中,我对它的绘图功能实不敢恭维,不过微软的MF开发人员很聪明,对位图方面的功能实现的就比较完善,这样做起图形应用来就不至于捉襟见肘了。
前段时间用.Net Compact Framework实现了一个奥运场馆查询(相关文章请参见:http://blog.csdn.net/yefanqiu/archive/2007/11/13/1882835.aspx),现在我们用.Net Micro Framework也实现一个,看看哪一个更炫。
image.png
image.png

(效果是不是比用.Net Compact Framework做的还棒!)
我这个程序脱胎于MF的示例文件NewPresentation,不过我对它进行了大刀阔斧的改进,原程序在实现菜单时至少需要两套大小不同的图片,现在我已经修改成仅需要一套图片了,此外我对tinyfnt中文字库的创建程序又进行了优化,可以更高效、更完美的创建字库了(相关文章请参见:http://blog.csdn.net/yefanqiu/archive/2007/11/01/1862300.aspx)。
如优化前菜单添加代码:

MenuItem menuItem1 = new MenuItem(Resources.BitmapResources.Vertical_Stack_Panel_Icon_Small, Resources.BitmapResources.Vertical_Stack_Panel_Icon, "Vertical Stack Panel", Resources.BitmapResources.Canvas_Panel_Icon);
      MenuItem menuItem2 = new MenuItem(Resources.BitmapResources.Horizontal_Stack_Panel_Icon_Small, Resources.BitmapResources.Horizontal_Stack_Panel_Icon, "Horizontal Stack Panel", Resources.BitmapResources.Canvas_Panel_Icon);
      MenuItem menuItem3 = new MenuItem(Resources.BitmapResources.Canvas_Panel_Icon_Small, Resources.BitmapResources.Canvas_Panel_Icon, "Canvas Panel", Resources.BitmapResources.Canvas_Panel_Icon);
      MenuItem menuItem4 = new MenuItem(Resources.BitmapResources.Diagonal_Panel_Icon_Small, Resources.BitmapResources.Diagonal_Panel_Icon, "Diagonal Panel", Resources.BitmapResources.Canvas_Panel_Icon);
      MenuItem menuItem5 = new MenuItem(Resources.BitmapResources.Scrollable_Panel_Icon_Small, Resources.BitmapResources.Scrollable_Panel_Icon, "Scrollable Panel", Resources.BitmapResources.Canvas_Panel_Icon);
      MenuItem menuItem6 = new MenuItem(Resources.BitmapResources.Free_Drawing_Panel_Icon_Small, Resources.BitmapResources.Free_Drawing_Panel_Icon, "Free Drawing Panel", Resources.BitmapResources.Canvas_Panel_Icon);
 
      // Add each of the menu items to the menu item panel
      m_MenuItemPanel.AddMenuItem(menuItem1);
      m_MenuItemPanel.AddMenuItem(menuItem2);
      m_MenuItemPanel.AddMenuItem(menuItem3);
      m_MenuItemPanel.AddMenuItem(menuItem4);
      m_MenuItemPanel.AddMenuItem(menuItem5);
 m_MenuItemPanel.AddMenuItem(menuItem6);

优化后的代码:

   m_MenuItemPanel.AddMenuItem(new MenuItem(Resources.BitmapResources.M1, "国家体育馆"));
   m_MenuItemPanel.AddMenuItem(new MenuItem(Resources.BitmapResources.M2, "北京大学体育馆"));
   m_MenuItemPanel.AddMenuItem(new MenuItem(Resources.BitmapResources.M3, "国家游泳中心-水立方"));
   m_MenuItemPanel.AddMenuItem(new MenuItem(Resources.BitmapResources.M4, "国家体育场-鸟巢"));
   m_MenuItemPanel.AddMenuItem(new MenuItem(Resources.BitmapResources.M5, "北京射击馆"));
   m_MenuItemPanel.AddMenuItem(new MenuItem(Resources.BitmapResources.M6, "顺义奥林匹克水上公园"));

实事求是的说,MF示例实现的图形菜单动画比我在北京2008奥运场馆速查中实现的要好,它的更规范,更具有通用性。相关代码如下:

// 菜单类
internal sealed class MenuItemPanel : Control
{
    private int _currentChild = 0;
    private int _width;
    private int _height;
    private int _animationStep;
    private Color ForeColor;
    public ArrayList MenuItemList;
 
    public MenuItemPanel(int width, int height, Color ForeColor,Color BackColor)
    {
        //背景色
        Background = new SolidColorBrush(BackColor);
        //前景色
        this.ForeColor = ForeColor;
        //大小
        _width = width;
        _height = height;
        //菜单选项集合
        MenuItemList = new ArrayList();
    }
   
    //添加菜单选项
    public void AddMenuItem(MenuItem menuItem)
    {
        MenuItemList.Add(menuItem);
    }
 
   //当前菜单选项索引
    public int CurrentChild
    {
        get { return _currentChild; }
        set
        {
            if (value > _currentChild) _animationStep = maxStep;             // 向右移动
            else if (value < _currentChild) _animationStep = -maxStep;       // 向左移动
            else _animationStep = 0;                                         // 没有移动
 
            if (value >= MenuItemList.Count) value = 0;                      // 菜单项是一个环状结构
            if (value < 0) value = MenuItemList.Count - 1;                      
 
            //开始重绘
            if (_animationStep != 0)
            {
                _currentChild = value;
                Invalidate();                                                //开始移动
            }
        }
    }
 
    static public int maxStep = 5;      //动画帧数
    const int xOffsetSeparation =2;     //每个菜单项的间距
    const int timerInterval = 20;       //移动每一个帧之间的动画时间ms
 
    //绘制菜单
    public override void OnRender(DrawingContext dc)
    {
        base.OnRender(dc);
 
        //获得图片宽度
        int largeX = ((MenuItem)MenuItemList[0]).ImageWidth + xOffsetSeparation;
 
        //起始坐标
        int x = (_width / 2) - ((largeX * 2) + (largeX / 2));
        int y =22;
 
        //缩放比例
        int scale = 0;
 
        //缩放比例的步长
        int scaleOffset = System.Math.Abs(_animationStep);
 
        //X方向移动
        x += _animationStep * 5;
 
        //绘背景
        dc.DrawImage(Resources.GetBitmap(Resources.BitmapResources.Main), 0, 0);
 
        #region //绘菜单图像
        for (int i = _currentChild - 2; i < _currentChild + 3; i++)
        {
            if (i == _currentChild) //中间图像
            {
                scale = maxStep - scaleOffset;
            }
            else //两边图像
            {
                if ((_animationStep < 0 && i == _currentChild + 1) || (_animationStep > 0 && i == _currentChild - 1))
                    scale = scaleOffset;
                else
                    scale = 0;
            }
 
            //当前菜单项
            MenuItem menuItem = null;
            if (i < 0) menuItem = (MenuItem)MenuItemList[MenuItemList.Count + i];
            else if (i > MenuItemList.Count - 1) menuItem = (MenuItem)MenuItemList[i - MenuItemList.Count];
            else menuItem = (MenuItem)MenuItemList[i];
 
            menuItem.Render(dc, x, y, scale);
            x += largeX;
        }
        #endregion
 
        #region //写菜单文本
        if (_width > 0)
        {
            int step = 20;
            int row = 125;
            if (_width < _height) step = 40;
 
            //写说明
            string text = ((MenuItem)MenuItemList[_currentChild]).Description;
            dc.DrawText(ref text, Resources.GetFont(Resources.FontResources.china2008), ForeColor, 10, row, _width - 20, step, TextAlignment.Center, TextTrimming.None);
        }
        #endregion
 
        //启动动画时钟
        StartAnimationTimer();
    }
 
    private DispatcherTimer _animationTimer;
    private void StartAnimationTimer()
    {
        if (_animationStep != 0)
        {
            if (_animationTimer == null)
            {
                _animationTimer = new DispatcherTimer(this.Dispatcher);
                _animationTimer.Interval = new TimeSpan(0, 0, 0, 0, timerInterval);
                //每隔一段时间触发该事件
                _animationTimer.Tick += new EventHandler(OnAnimationTimer);
            }
            _lastTick = DateTime.Now.Ticks;
            _animationTimer.Start();
        }
    }
    long _lastTick = 0;
    private void OnAnimationTimer(object o, EventArgs e)
    {
        _animationTimer.Stop();
        long ms = ((DateTime.Now.Ticks - _lastTick) / 10000);
        _lastTick = DateTime.Now.Ticks;
        int increment = (int)(ms / timerInterval);
 
        if (increment < 1) increment = 1;
        else if (increment > maxStep) increment = maxStep;
 
        if (_animationStep < 0) _animationStep += increment;
        else if (_animationStep > 0) _animationStep -= increment;
 
        //重新触发OnRender函数的执行
        Invalidate();
    }
 
    //窗体可用尺寸
    protected override void MeasureOverride(int availableWidth, int availableHeight, out int desiredWidth, out int desiredHeight)
    {
        desiredWidth = _width;
        desiredHeight = _height;
    }
}
 
// 菜单选项类
internal sealed class MenuItem : Control
{
    private Bitmap _image;         // 菜单图标
    private string _description;   // 菜单说明
    private int[] _widthSteps;     // 宽度步长数组
    private int[] _heightSteps;    // 高度步长数组
    public int ImageWidth;         // 图像宽度
    public int ImageHeight;        // 图像高度
    private float fScale = (float)0.8;   // 缩小因子
    public int SmallWidth;         // 缩小后的宽度
    public int SmallHeight;        // 缩小后的高度
 
    public MenuItem()
    {
    }
    public MenuItem(Resources.BitmapResources rBitmap, string description)
    {
        //菜单图像
        _image = Resources.GetBitmap(rBitmap);
       
        //图像尺寸
        ImageWidth = _image.Width;
        ImageHeight = _image.Height;
        SmallWidth = (int)(fScale * ImageWidth);
        SmallHeight = (int)(fScale * ImageHeight);
 
        //菜单说明
        _description = description;
 
        //创建中间动画帧尺寸数组
        _widthSteps = new int[MenuItemPanel.maxStep];
        _heightSteps = new int[MenuItemPanel.maxStep];
 
        //动画变化总大小
        int wDiff = ImageWidth - SmallWidth;
        int hDiff = SmallHeight - SmallHeight;
 
        //保存每次变化的大小
        for (int i = 1; i < MenuItemPanel.maxStep; i++)
        {
            _widthSteps[i] = (wDiff / MenuItemPanel.maxStep) * i;
            _heightSteps[i] = (hDiff / MenuItemPanel.maxStep) * i;
        }
 
    }
    //菜单说明
    public string Description
    {
        get { return _description; }
        set { _description = value; }
    }
    //菜单绘制
    public void Render(DrawingContext dc, int x, int y, int scale)
    {
        // 图像必须存在
        if (_image != null)
        {
            if (scale == MenuItemPanel.maxStep)
            {
                Width = ImageWidth;
                Height = ImageHeight;
                dc.DrawRectangle(new SolidColorBrush(Color.Black), new Pen(Color.Black), x+2, y+2, Width, Height);
                dc.DrawImage(_image, x, y);
            }
            else
            {
                if (scale == 0)
                {
                    Width = SmallWidth;
                    Height = SmallHeight;
                    x += ((ImageWidth - Width) / 2);
                    y += ((ImageHeight - Height) / 2);
                    dc.DrawRectangle(new SolidColorBrush(Color.Black), new Pen(Color.Black), x + 2, y + 2, Width, Height);
                    dc.Bitmap.StretchImage(x, y, _image, Width, Height, 255);
                 }
                else
                {
                    int wDiff = ImageWidth - SmallWidth;
                    int hDiff = SmallHeight - SmallHeight;
                    Width = SmallWidth + _widthSteps[scale];
                    Height = SmallHeight + _heightSteps[scale];
                    x += ((ImageWidth - Width) / 2);
                    y += ((ImageHeight - Height) / 2);
                    dc.DrawRectangle(new SolidColorBrush(Color.Black), new Pen(Color.Black), x + 2, y + 2, Width, Height);
                    dc.Bitmap.StretchImage(x, y, _image, Width, Height, 255);
                }
            }
        }
    }
}

本程序的源代码下载链接:http://www.sky-walker.com.cn/yefan/SourceCode/YFPresentation.rar
有条件的网友可以和微软提供的示例NewPresentation对比一下看看,也许更能看出它们的异同。有时间我在把这个类封装成一个控件(基于.Net CF),这样在windows和wince平台就都能使用了。

相关文章
|
4月前
|
算法 Java 调度
|
7月前
|
Kubernetes 关系型数据库 数据库
.netcore应用容器化部署
.netcore应用容器化部署
|
7月前
|
Kubernetes 数据库 C++
.netcore应用在WSL中的容器化部署
前面,我们讲解了如何在wsl中安装数据库,.netcore运行时,以及如何发布一个.netcore应用,为了构成一个完整的小系列,本节,我们来学习一下,如何将.netcore应用在WSL中容器化。
|
7月前
|
安全 C# 开发工具
模拟.NET应用场景,综合应用反编译、第三方库调试、拦截、一库多版本兼容方案
模拟.NET实际应用场景,综合应用三个主要知识点:一是使用dnSpy反编译第三库及调试,二是使用Lib.Harmony库实现第三库拦截、伪造,三是实现同一个库支持多版本同时引用。
模拟.NET应用场景,综合应用反编译、第三方库调试、拦截、一库多版本兼容方案
|
前端开发 Ubuntu Linux
【.NET6+Avalonia】开发支持跨平台的仿WPF应用程序以及基于ubuntu系统的演示
随着跨平台越来越流行,.net core支持跨平台至今也有好几年的光景了。但是目前基于.net的跨平台,大多数还是在使用B/S架构的跨平台上;至于C/S架构,大部分人可能会选择QT进行开发,或者很早之前还有一款Mono可以支持.NET开发者进行开发跨平台应用。
837 0
【.NET6+Avalonia】开发支持跨平台的仿WPF应用程序以及基于ubuntu系统的演示
|
8天前
|
开发框架 前端开发 JavaScript
采用C#.Net +JavaScript 开发的云LIS系统源码 二级医院应用案例有演示
技术架构:Asp.NET CORE 3.1 MVC + SQLserver + Redis等 开发语言:C# 6.0、JavaScript 前端框架:JQuery、EasyUI、Bootstrap 后端框架:MVC、SQLSugar等 数 据 库:SQLserver 2012
|
6月前
|
Go
Golang 语言怎么使用 net/http 标准库开发 http 应用?
Golang 语言怎么使用 net/http 标准库开发 http 应用?
26 0
|
7月前
|
关系型数据库 MySQL 容器
.netcore应用容器化时更改Expose端口无法访问
.netcore应用容器化时更改Expose端口无法访问
|
4月前
|
小程序 安全 JavaScript
.NET微信网页开发之通过UnionID机制解决多应用用户帐号统一问题
.NET微信网页开发之通过UnionID机制解决多应用用户帐号统一问题
.NET微信网页开发之通过UnionID机制解决多应用用户帐号统一问题