首页 > 技术文章 > 1.窗体与界面设计-窗体控制技术

iwanc 2013-06-28 18:55 原文

主要介绍如何动态创建窗体,在窗体关闭前加入提示信息以及任意控制窗体移动等相关技术,这些都是在实际开发中被广泛应用的技术。

044 在关闭窗口前加入确认对话框

窗口正要关闭但是没有关闭之前会触发 FormClosing 事件,该事件中的参数 FormClosing EventArgs e 中包含 Cancel 属性,如果设置该属性为 True,窗口将不会被关闭。因此在该事件处理代码中可以提示用户是否关闭程序,如果用户不想关闭程序,则设置该参数为 True。利用 MessageBox 参数的返回值可以知道用户所选中的按钮。

创建一个项目,默认窗体为 Form1。

namespace _044_QueryClose
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (MessageBox.Show("将要关闭窗体,是否继续?","询问",MessageBoxButtons.YesNo) == DialogResult.Yes)
            {
                e.Cancel = false;   //不取消事件的值
            } 
            else
            {
                e.Cancel = true;    //取消事件的值
            }
        }
    }
}

045 通过子窗体刷新父窗体

本实例在子窗体刷新父窗体时,主要应用事件来对主窗体进行刷新。当子窗体产生相对应的更新操作时,通过子窗体的一个方法,触发主窗体中对应的处理事件。

1.创建一个项目,修改默认窗体为 ChildRefurbishParent;添加一个 Windows 窗体,将其命名为 ChildWindow。

2.在 ChildRefurbishParent 窗体上添加一个 DataGridView 控件和一个 MenuStrip 控件。设置 ChildRefurbishParent 窗体的 MainMenuStrip 属性为 menuStrip1、WindowState 属性为 Maximized 以及 IsMdiContainer 属性为 True。在 ChildWindow 窗体中添加两个 GroupBox 控件、5个 Label 控件、4个 TextBox 控件、一个 ComboBox 控件以及3个 Button 控件。

注意:在做与数据库有关的操作时,需要引用命名空间 System.Data.SqlClient。

//ChildRefurbishParent窗体代码
namespace _045_ChildRefurbishParent
{
    public partial class ChildRefurbishParent : Form
    {
        public ChildRefurbishParent()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 本实例应该设置主窗体的IsMdiContainer属性为true、MainMenuStrip属性为所添加的菜单栏、WindowState属性为Maximized、窗体名称为ChildRefurbishParent、设置AllowUserToAddRows属性为false
        /// </summary>

        #region 声明的变量
        public static bool flag = false;//标识是否创建新的子窗体
        ChildWindow BabyWindow = new ChildWindow();//实例化一个子窗体
        DataSet PubsSet = new DataSet(); //定义一个数据集对象
        public static string[] IDArray; //声明一个一维字符串数组
        public DataTable IDTable;       //声明一个数据表对象
        SqlDataAdapter IDAdapter;        //声明一个数据读取器对象
        SqlDataAdapter PubsAdapter;       //声明一个数据读取器对象
        SqlConnection ConnPubs;           //声明一个数据库连接对象
        SqlCommand PersonalInformation;    //声明一个执行SQL语句的对象
        #endregion

        //在ChildRefurbishParent窗体的加载过程中,需要显示数据库中的数据
        private void ChildRefurbishParent_Load(object sender, EventArgs e)
        {
            //string ConnString = "Data Source=.;DataBase=db_01;integrated security=sspi";//本地数据库连接字符串
            string ConnString = "server=55.66.77.88;user id=sa;pwd=123456;DataBase=db_01";//远程数据库连接字符串
            string AdapterString = "select userId as 编号,userName as 姓名 ,phone as 电话,address as 住址 from tb_01";//用于查询的字符串
            string IDString = "select userID from tb_01";//读取数据库中用户的ID编号字符串
            ConnPubs = new SqlConnection(ConnString);//建立数据库连接
            PubsAdapter = new SqlDataAdapter(AdapterString, ConnPubs);//创建PubsAdapter数据读取器
            IDAdapter = new SqlDataAdapter(IDString, ConnPubs);//用于读取用户编号的读取器
            PubsAdapter.Fill(PubsSet, "Authors");//填充PubsSet数据集
            IDAdapter.Fill(PubsSet, "ID");//填充PubsSet数据集
            DataTable PubsTable = PubsSet.Tables["Authors"];//将数据写入PubsTable表
            IDTable = PubsSet.Tables["ID"];//将数据写入ID表
            IDArray = new string[IDTable.Rows.Count];//为数组定义最大长度
            dataGridView1.DataSource = PubsTable.DefaultView;//设置dataGridView1的数据源
            for (int i = 0; i < IDTable.Rows.Count; i++)   //循环遍历数据表中的每一行数据
            {
                for (int j = 0; j < IDTable.Columns.Count; j++)//循环遍历数据表中的每一列数据
                {
                    IDArray[i] = IDTable.Rows[i][j].ToString(); //将数据表中的数据添加至一个一维数组
                }
            }
        }

        #region 单击菜单“操作类型”中的“添加与删除”选项,显示出子窗体
        private void AddandDelete_Click(object sender, EventArgs e)
        {
            if (flag == false)//判断标识的值决定是否创建窗体
            {
                CreateChildWindow();//创建子窗体
            }
            for (int i = 0; i < this.dataGridView1.Controls.Count; i++)//循环遍历DataGridView控件上的控件集
            {
                if (this.dataGridView1.Controls[i].Name.Equals(BabyWindow.Name))//当存在子窗体时
                {
                    flag = true;//改变标识Flag的值
                    break;//退出循环体
                }
            }
        }
        #endregion

        private void ExitProject_Click(object sender, EventArgs e)
        {
            Application.Exit();//退出本程序
        }

        #region 创建子窗体的CreateChildWindow方法
        public void CreateChildWindow()
        {
            ChildWindow BabyWindow = new ChildWindow();//实例化一个子窗体
            BabyWindow.MdiParent = this;//设置子窗体的父窗体为当前窗体
            this.dataGridView1.Controls.Add(BabyWindow);//在DataGridView控件中添加子窗体
            BabyWindow.UpdateDataGridView += new EventHandler(BabyWindow_UpdateDataGridView);
            BabyWindow.Show();//显示子窗体
        }

        //子窗体通过事件BabyWindow_UpdateDataGridView来实现对主窗体数据的更新
        void BabyWindow_UpdateDataGridView(object sender, EventArgs e)
        {
            if (ChildWindow.GlobalFlag == false)    //当单击删除按钮时
            {
                if (ConnPubs.State == ConnectionState.Closed) //当数据库处于断开状态时
                {
                    ConnPubs.Open();                //打开数据库的连接
                }
                string AfreshString = "delete tb_01 where userID=" + ChildWindow.DeleteID.Trim();//定义一个删除数据的字符串
                PersonalInformation = new SqlCommand(AfreshString, ConnPubs); //执行删除数据库字段
                PersonalInformation.ExecuteNonQuery(); //执行SQL语句并返回受影响的行数
                ConnPubs.Close();                     //关闭数据库
                DisplayData();                          //显示数据库更新后的内容
                MessageBox.Show("数据删除成功!", "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);//弹出删除数据成功的提示
            }
            else
            {
                if (ConnPubs.State == ConnectionState.Closed) //当数据库处于关闭状态时
                {
                    ConnPubs.Open();                        //打开数据库
                }
                string InsertString = "insert into tb_01 values('" + ChildWindow.idContent + "','" + ChildWindow.nameContent + "','" + ChildWindow.phoneContent + "','" + ChildWindow.addressContent + "')";//定义一个插入数据的字符串变量
                PersonalInformation = new SqlCommand(InsertString, ConnPubs);//执行插入数据库字段
                PersonalInformation.ExecuteNonQuery();//执行SQL语句并返回受影响的行数
                ConnPubs.Close();                    //关闭数据库
                DisplayData();                         //显示更新后的数据
                MessageBox.Show("数据添加成功!", "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);//弹出添加成功的提示信息
            }
        }
        #endregion

        #region 在更改主窗体中的数据时,需要随时显示数据库中的数据
        public void DisplayData()
        {
            PubsSet.Clear();
            //string ConnString = "Data Source=.;DataBase=db_01;integrated security=sspi";//本地数据库连接字符串
            string ConnString = "server=55.66.77.88;user id=sa;pwd=123456;DataBase=db_01";//远程数据库连接字符串
            ConnPubs = new SqlConnection(ConnString);//建立数据库连接
            string DisplayString = "select userId as 编号,userName as 姓名 ,phone as 电话,address as 住址 from tb_01";//定义读取数据库的字段
            SqlDataAdapter PersonalAdapter = new SqlDataAdapter(DisplayString, ConnPubs); //定义一个读取数据库数据的读取器
            PersonalAdapter.Fill(PubsSet, "DisplayTable"); //向表DisplayTable中填充数据
            dataGridView1.DataSource = PubsSet.Tables["DisplayTable"].DefaultView;//设定DataGridView控件的数据源
        }
        #endregion
    }
}
//ChildWindow窗体代码
namespace _045_ChildRefurbishParent
{
    public partial class ChildWindow : Form
    {
        public ChildWindow()
        {
            InitializeComponent();
        }

        ///<summary>
        /// 本实例仅可创建一个窗口,因此在这里屏蔽关闭按钮;最大化后没有实际意义,因此关闭MaximizeBox属性值为False
        ///</summary>

        #region 变量的声明
        public event EventHandler UpdateDataGridView = null;//定义一个处理更新DataGridView控件内容的方法
        public static string DeleteID;  //定义一个表示删除数据编号的字符串
        public static string idContent; //该变量用来存储数据编号
        public static string nameContent;//该变量用来存储姓名
        public static string phoneContent;//该变量用来存储电话
        public static string addressContent;//该变量用来存储住址
        public static bool GlobalFlag; //该变量用来标识是否创建新的子窗体
        #endregion

        //UpdateData方法用来触发主窗体中的处理事件
        protected void UpdateData()
        {
            if (UpdateDataGridView != null)//当触发更新DataGridView事件时
            {
                UpdateDataGridView(this, EventArgs.Empty);//更新DataGridView控件中的内容
            }
        }

        //在窗体的关闭事件中标识此窗体已处于关闭状态
        private void ChildWindow_FormClosing(object sender, FormClosingEventArgs e)
        {
            ChildRefurbishParent.flag = false; //设定该值为false表示可以创建新窗体
        }

        //当窗体加载时,在ComboBox控件中加载数据库中的数据编号
        private void ChildWindow_Load(object sender, EventArgs e)
        {
            for (int i = 0; i < ChildRefurbishParent.IDArray.Length; i++) //循环遍历数组中的每一个元素
            {
                comboBox1.Items.Add(ChildRefurbishParent.IDArray[i].ToString());//向Combobox控件中添加内容
                comboBox1.SelectedIndex = 0;//设定当前选中项的索引为0
            }
        }

        //在ComboBox控件中选定将要删除的记录,单击“删除”按钮删除数据
        private void deleteButton_Click(object sender, EventArgs e)
        {
            GlobalFlag = false; //设定全局变量表示为false
            if (comboBox1.Items.Count > 1)//当ComboBox中剩不小于2条内容时
            {
                DeleteID = comboBox1.SelectedItem.ToString();//将选中项转化为int型
                if (comboBox1.Items.Count != 0)//当ComboBox中剩1条内容时
                {
                    comboBox1.Items.Remove(comboBox1.SelectedItem);
                    comboBox1.SelectedIndex = 0;
                }
            }
            UpdateData();//更新Combobox控件中的内容
        }

        //当在文本框中输入的错误信息过多时,单击“取消”按钮即可清空输入的所有内容
        private void cancelButton_Click(object sender, EventArgs e)
        {
            id.Clear(); //清空编号文本框中的内容
            name.Clear();//清空姓名文本框中的内容
            phone.Clear();//清空电话号码文本框中的内容
            address.Clear();//清空居住地址文本框中的内容
            id.Focus();//设定当前鼠标的焦点在编号文本框中
        }

        //当在文本框中输入添加的信息后,单击“提交”按钮数据即可更新到主窗体重
        private void submitButton_Click(object sender, EventArgs e)
        {
            GlobalFlag = true; //设定标识的值为true
            if (!(comboBox1.Items.Equals(idContent)))//当Combobox控件中不存在将添加的信息时
            {
                comboBox1.Items.Add(idContent);//在Combobox控件中添加一条记录
            }
            UpdateData();
        }

        //当窗体中文本框的内容发生改变时,应该保存对应文本框的值,这样方便数据库的更新
        private void id_TextChanged(object sender, EventArgs e)
        {
            idContent = id.Text; //保存新添加记录的编号
        }

        private void name_TextChanged(object sender, EventArgs e)
        {
            nameContent = name.Text;//保存填入的姓名
        }

        private void phone_TextChanged(object sender, EventArgs e)
        {
            phoneContent = phone.Text;//保存填入的电话号码
        }

        private void address_TextChanged(object sender, EventArgs e)
        {
            addressContent = address.Text;//保存填入的地址信息
        }
    }
}

046 拖动无边框窗体

本实例主要用到 Windows 的两个 API 函数,即 ReleaseCapture 和 SendMessage。

注意:当调用 Windows 的 API 函数时,需要引用命名空间 System.Runtime.InteropServices。

创建一个项目,默认窗体为 Form1,在 Form1 窗体上添加一个 ContextMenuStrip 控件。设置 Form1 窗体的 ContextMenuStrip 属性为 contextMenuStrip1。

namespace _046_DragNoFrameWindow
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 本实例需设置窗体的FormBorderStyle属性为None、设置ContextMenuStrip属性为当前添加的实例
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>

        #region 本程序中用到的API函数
        [DllImport("user32.dll")]
        public static extern bool ReleaseCapture();  //用来释放被当前线程中某个窗口捕获的光标

        [DllImport("user32.dll")]
        public static extern bool SendMessage(IntPtr hwdn, int wMsg, int mParam, int lParam);//向指定的窗体发送Windows消息
        #endregion

        #region 本程序中需要声明的变量
        public const int WM_SYSCOMMAND = 0x0112;    //该变量表示将向Windows发送的消息类型
        public const int SC_MOVE = 0xF010;          //该变量表示发送消息的附加消息
        public const int HTCAPTION = 0x0002;        //该变量表示发送消息的附加消息
        #endregion

        private void ExitContext_Click(object sender, EventArgs e)
        {
            Application.Exit();   //退出本程序
        }

        private void Form1_MouseDown(object sender, MouseEventArgs e)
        {
            ReleaseCapture();   //用来释放被当前线程中某个窗口捕获的光标
            SendMessage(this.Handle, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0); //向Windows发送拖动窗体的消息
        }
    }
}

推荐阅读