.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月前
|
存储 Shell Linux
快速上手基于 BaGet 的脚本自动化构建 .net 应用打包
本文介绍了如何使用脚本自动化构建 `.net` 应用的 `nuget` 包并推送到指定服务仓库。首先概述了 `BaGet`——一个开源、轻量级且高性能的 `NuGet` 服务器,支持多种存储后端及配置选项。接着详细描述了 `BaGet` 的安装、配置及使用方法,并提供了 `PowerShell` 和 `Bash` 脚本实例,用于自动化推送 `.nupkg` 文件。最后总结了 `BaGet` 的优势及其在实际部署中的便捷性。
183 10
|
3月前
使用的是.NET Framework 4.0,并且需要使用SMTP协议发送电子邮件
使用的是.NET Framework 4.0,并且需要使用SMTP协议发送电子邮件
61 1
|
2月前
|
开发框架 监控 .NET
【Azure App Service】部署在App Service上的.NET应用内存消耗不能超过2GB的情况分析
x64 dotnet runtime is not installed on the app service by default. Since we had the app service running in x64, it was proxying the request to a 32 bit dotnet process which was throwing an OutOfMemoryException with requests >100MB. It worked on the IaaS servers because we had the x64 runtime install
|
2月前
|
JSON 算法 安全
JWT Bearer 认证在 .NET Core 中的应用
【10月更文挑战第30天】JWT(JSON Web Token)是一种开放标准,用于在各方之间安全传输信息。它由头部、载荷和签名三部分组成,用于在用户和服务器之间传递声明。JWT Bearer 认证是一种基于令牌的认证方式,客户端在请求头中包含 JWT 令牌,服务器验证令牌的有效性后授权用户访问资源。在 .NET Core 中,通过安装 `Microsoft.AspNetCore.Authentication.JwtBearer` 包并配置认证服务,可以实现 JWT Bearer 认证。具体步骤包括安装 NuGet 包、配置认证服务、启用认证中间件、生成 JWT 令牌以及在控制器中使用认证信息
126 2
|
3月前
|
开发框架 缓存 监控
NET Framework 到 .NET 5/6 的迁移是重大的升级
本文详细介绍了从 .NET Framework 4.8 迁移到 .NET 5/6 的过程,通过具体案例分析了迁移策略与最佳实践,包括技术栈评估、代码迁移、依赖项更新及数据库访问层的调整,强调了分阶段迁移、保持代码可维护性及性能监控的重要性。
67 3
|
3月前
|
机器学习/深度学习 编解码 算法
【小样本图像分割-4】nnU-Net: Self-adapting Framework for U-Net-Based Medical Image Segmentation
《nnU-Net: 自适应框架用于基于U-Net的医学图像分割》是一篇2018年的论文,发表在Nature上。该研究提出了一种自适应的医学图像分割框架nnU-Net,能够自动调整模型的超参数以适应不同的数据集。通过2D和3D U-Net及级联U-Net的组合,nnU-Net在10个医学分割数据集上取得了卓越的性能,无需手动调整。该方法强调数据增强、预处理和训练策略等技巧,为医学图像分割提供了一个强大的解决方案。
111 0
【小样本图像分割-4】nnU-Net: Self-adapting Framework for U-Net-Based Medical Image Segmentation
winform .net6 和 framework 的图表控件,为啥项目中不存在chart控件,该如何解决?
本文讨论了在基于.NET 6和.NET Framework的WinForms项目中添加图表控件的不同方法。由于.NET 6的WinForms项目默认不包含Chart控件,可以通过NuGet包管理器安装如ScottPlot等图表插件。而对于基于.NET Framework的WinForms项目,Chart控件是默认存在的,也可以通过NuGet安装额外的图表插件,例如LiveCharts。文中提供了通过NuGet添加图表控件的步骤和截图说明。
winform .net6 和 framework 的图表控件,为啥项目中不存在chart控件,该如何解决?
|
4月前
|
数据采集 JSON API
.NET 3.5 中 HttpWebRequest 的核心用法及应用
【9月更文挑战第7天】在.NET 3.5环境下,HttpWebRequest 类是处理HTTP请求的一个核心组件,它封装了HTTP协议的细节,使得开发者可以方便地发送HTTP请求并接收响应。本文将详细介绍HttpWebRequest的核心用法及其实战应用。
171 6
|
5月前
|
数据库 C# 开发者
WPF开发者必读:揭秘ADO.NET与Entity Framework数据库交互秘籍,轻松实现企业级应用!
【8月更文挑战第31天】在现代软件开发中,WPF 与数据库的交互对于构建企业级应用至关重要。本文介绍了如何利用 ADO.NET 和 Entity Framework 在 WPF 应用中访问和操作数据库。ADO.NET 是 .NET Framework 中用于访问各类数据库(如 SQL Server、MySQL 等)的类库;Entity Framework 则是一种 ORM 框架,支持面向对象的数据操作。文章通过示例展示了如何在 WPF 应用中集成这两种技术,提高开发效率。
78 0
|
5月前
|
开发者 API Windows
从怀旧到革新:看WinForms如何在保持向后兼容性的前提下,借助.NET新平台的力量实现自我进化与应用现代化,让经典桌面应用焕发第二春——我们的WinForms应用转型之路深度剖析
【8月更文挑战第31天】在Windows桌面应用开发中,Windows Forms(WinForms)依然是许多开发者的首选。尽管.NET Framework已演进至.NET 5 及更高版本,WinForms 仍作为核心组件保留,支持现有代码库的同时引入新特性。开发者可将项目迁移至.NET Core,享受性能提升和跨平台能力。迁移时需注意API变更,确保应用平稳过渡。通过自定义样式或第三方控件库,还可增强视觉效果。结合.NET新功能,WinForms 应用不仅能延续既有投资,还能焕发新生。 示例代码展示了如何在.NET Core中创建包含按钮和标签的基本窗口,实现简单的用户交互。
85 0