PDA开发系列:开发框架的搭建(上)

     很多的手机软件,在底部或者顶部都有两个菜单,左边一个是功能菜单,右边一个是“返回”或者“退出”的按钮,这个软件也不列外,为了方便开发,我做了一个集成。

     要实现的最终样式大概是这样的:

     2010 10 19_10 45 16_0035_111g

     顶部的左边是功能菜单;顶部的右边是“返回”或者“退出”;顶部的中间显示相应的功能描述;中间是一个Panel容器,用来加载不同的用户控件。下面,我们就来一步步实现这些需求。

     主窗体

     打开VS2005,新建一个智能设备应用程序项目,将窗体的ControlBox属性设置成false,FormBorderStyle属性设置成none.然后拖放两个Panel,一个据顶,一个居中,然后再拖放两个按钮到顶部的Panel中,一个居左,一个居右,中间放一个Label用来显示功能描述。如下图:

1

(为了简单起见,在这里,我直接在左右两边放了个button,显得十分的简陋,在实际的项目中,大家可以考虑封装成一个控件,做出更加美观的效果)

      要实现“返回”的功能,我们必须在主窗体里面放置一个容器,来保存历史操作,在这里,我用Stack来保存。容器有了,我们还缺少两个方法,一个是把历史操作放进去(即前进)的方法,一个是取出历史操作(即返回)的方法。同时,我们也添加一个父用户控件ucBaseControl,将返回的操作与返回按钮关联起来,代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
 
namespace PDA
{
    public partial class MainForm : Form
    {
        private Stack<ucBaseControl> StackList = new Stack<ucBaseControl>();
        public MainForm()
        {
            InitializeComponent();
        }
 
        /// <summary>
        /// 控件跳转
        /// </summary>
        /// <param name="ctl">用户控件</param>
        public void ShowForm(ucBaseControl ctl)
        {
            if (StackList == null)
            {
                StackList = new Stack<ucBaseControl>();
            }
 
            ucBaseControl uc = null;
            if (this.pnlMain.Controls.Count == 0)
            {
                return;
            }
            else
            {
                uc = this.pnlMain.Controls[0] as ucBaseControl;
            }
            if (uc != null)
            {
                if (!StackList.Contains(uc))
                {
                    StackList.Push(uc);
                    this.btnReturn.Text = "返回";
                }
                this.pnlMain.Controls.Clear();
                ctl.Dock = DockStyle.Fill;
                this.pnlMain.Controls.Add(ctl);
            }
        }
 
        /// <summary>
        /// 返回
        /// </summary>
        public void Return()
        {
            //返回按钮的事件
            if (StackList != null && StackList.Count > 0)
            {
                ucBaseControl ctl = StackList.Pop();
                if (StackList != null && StackList.Count > 0)
                {
                    this.btnReturn.Text = "返回";
                }
                else
                {
                    this.btnReturn.Text = "退出";
                }
                this.ShowForm(ctl);
            }
        }
 
        private void btnReturn_Click(object sender, EventArgs e)
        {
            Return();
        }
    }
}

至此,“返回”功能仿佛就已经完成了。下面我们再来看“功能”按钮和模块功能描述该怎么实现。

     ucBaseControl

     我知道,每一个功能模块都功能菜单和模块名称,但却都各不相同的功能,所以我们在ucBaseControl里面添加一个两个抽象方法,让各功能模块去实现自己的菜单和给出自己的功能描述,然后再赋值给ucBaseControl控件的ContextMenu和Text属性,所以,我们想到在ucBaseControl中添加如下代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
 
namespace PDA
{
    public abstract partial class ucBaseControl : UserControl
    {
        public ucBaseControl()
        {
            InitializeComponent();
            ContextMenu menu = null;
            string titel = string.Empty;
            OnFunction(ref menu);
            OnTitel(ref titel);
 
            this.ContextMenu = menu;
            this.Text = titel;
        }
 
        /// <summary>
        /// 功能菜单的方法
        /// </summary>
        /// <param name="contextMenu"></param>
        protected abstract void OnFunction(ref ContextMenu contextMenu);
        /// <summary>
        /// 模块标题
        /// </summary>
        /// <param name="titel"></param>
        protected abstract void OnTitel(ref string titel);
 
    }
}

我们在子控件中有类似如下的代码来对这两个方法进行实现:

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
 
namespace PDA
{
    public partial class UserControl1 : PDA.ucBaseControl
    {
        public UserControl1():base()
        {
            InitializeComponent();
        }
 
        protected override void OnFunction(ref ContextMenu contextMenu)
        {
            if (contextMenu == null)
            {
                contextMenu = new ContextMenu();
            }
            else
            {
                contextMenu.MenuItems.Clear();
            }
 
            MenuItem item = new MenuItem();
            item.Text = "跳转到Test2";
            item.Click += new EventHandler(item_Click);
            contextMenu.MenuItems.Add(item);
        }
 
        protected override void OnTitel(ref string titel)
        {
            titel = "Test1";
        }
 
        void item_Click(object sender, EventArgs e)
        {
        }
    }
}
 

请注意,子控件的构造函数必须继承基类构造函数,原因大家都知道,不继承的话,我们写在基类构造函数中的两个抽象方法就不会执行。现在新的问题产生了,我们该如何在item_Click事件中做功能模块的跳转呢?在这里,我们首先需要获得当前用户控件所在的窗体,这里面可不想PC上的winform开发,用户控件直接有ParentForm属性,在这里面,我们需要自己去写,所以,我们在ucBaseControl里面添加如下代码,已获得用户控件所在的窗体:

/// <summary>
/// 获取用户控件所在的窗体
/// </summary>
protected MainForm ParentForm
{
    get
    {
        Control frm = this.Parent;
        while (!(frm is MainForm))
        {
            frm = frm.Parent;
        }
        return frm as MainForm;
    }
}

至此,我们所有的准备工作就完成了,我们来测试我们的框架吧!

    测试后,大家会发现几个问题:

    1.功能按钮不是一般的难用。

    2.我们的模块菜单都是在够好函数里面加载的,也就是说,在返回的时候,菜单不会重新加载,然而在很多时候,比方说,一个表单,在菜单里面提交后,再返回时,菜单中的“提交”按钮应该是灰色的。

    3.在控件跳转的时候,如果跳转的用户控件中的内容比较的多,窗体会卡好一会,要是能像AJAX一样,在加载的过程中,放一个loading图片就好了。

    这些答案将在下篇中一一解答。

测试代码下载:测试代码

作者:HOH
出处:http://hoh.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
posted @ 2010-10-23 21:50 HOH 阅读(101) 评论(0) 编辑 收藏
发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 1859506 NEZVFxhnp2M=