Winform技术要点及案例项目开发小结

近期帮朋友开发了一个小型WINFORM的软件,即在软件窗体中显示相关表格的数据。由于长时期未操作WINFORM了,有点手生,尤其是对于EXCEL表格的操作,在没有第三方控件辅助的基础上,更感到了吃力。 但所幸功夫不负有心人, 终于让我找到了相关的解决方案。 现总结一下此次项目开发的经验教训,以便后期借鉴。


1.winform虽然目前已不再是主流的开发技术, 但对于小型的需求,仍不失为一个不错的选择,尤其是对于小型单机办公型应用程序,其界面的友好性,及相关控件操作的简易性,很适合开发小型的桌面应用程序。


2.闪屏现象解决方案。由于在窗体中加入大量图片,以及绘图等操作,在程序启动或加载某个界面时出现屏幕闪烁的问题。为了解决这种现象,可以在窗体构造函数中加入如下代码,以解决闪屏现象。其中第一行一般为程序自带代码, 后面几行主要是解决屏幕变化出现的闪烁现象,即进行一定的缓冲操作。

             InitializeComponent();

            this.DoubleBuffered = true;//设置本窗体
            SetStyle(ControlStyles.UserPaint, true);
            SetStyle(ControlStyles.AllPaintingInWmPaint, true); // 禁止擦除背景.
            SetStyle(ControlStyles.DoubleBuffer, true); // 双缓冲


3.窗体容器panel的使用, 即如果需要对窗体背景图片进行分割,可以利用容器控件进行适当的操作。


4.基本控件的使用,如control,label,textbox等等。


5.datagridview控件的使用。对于没有格式要求的数据显示,datagridview及listview可以做为基本的显示控件,且可以通过调整相关的属性,如控件头部隐藏,边框隐藏,填充窗体的方式等进行简单的格式调整,但对于合并单元格等操作,但一般需要进行绘图等复杂操作,相应的代码较为复杂。

5.1 datagridview的读取数据操作。

string str = @"d:\cpcx\cpqlc.xls";//也可以通过打开文件对话框进行选择文件。

DataTable dt = ExcelUp(File); //  将excel文件读取到DATATABLE
dataGridView1.AutoGenerateColumns = true;  //设置datagridview自动增加列,即新添加的数据自动新添加列。
dataGridView1.DataSource = dt;  //设置数据源。

public DataTable ExcelUp(string fileName)
        {
            string filePath = fileName;//读取excel文件路径;

            DataTable dt = GetDataTable("Sheet1", filePath);

            return dt;

        }

protected DataTable GetDataTable(string strSheetName, string strExcelFileName)
        {
            //源的定义,即ADO的读取数据操作。

           //string strConn = "Provider=Microsoft.Jet.OleDb.4.0;" + "data source=" + Server.MapPath("ExcelFiles/MyExcelFile.xls") + ";Extended Properties='Excel 8.0; HDR=Yes; IMEX=1'";//此连接只能操作Excel2007之前(.xls)文件

           string strConn = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;" + "Data Source={0};" + "Extended Properties='Excel 8.0;HDR=NO;IMEX=1';", strExcelFileName);//此连接可以操作.xls与.xlsx文件 (支持Excel2003 和 Excel2007 的连接字符串).

//备注: "HDR=yes;"是说Excel文件的第一行是列名而不是数据,"HDR=No;"正好与前面的相反。
//      "IMEX=1 "如果列中的数据类型不一致,使用"IMEX=1"可必免数据类型冲突。



特别注意

Extended Properties='Excel 8.0;HDR=yes;IMEX=1'

A: HDR ( HeaDer Row )设置

若指定值为Yes,代表 Excel 档中的工作表第一行是栏位名称

若指定值為 No,代表 Excel 档中的工作表第一行就是資料了,沒有栏位名称

B:IMEX ( IMport EXport mode )设置

IMEX 有三种模式,各自引起的读写行为也不同,容後再述:

0 is Export mode

1 is Import mode

2 is Linked mode (full update capabilities)

我这里特别要说明的就是 IMEX 参数了,因为不同的模式代表著不同的读写行为:

当IMEX=0 时为“汇出模式”,这个模式开启的 Excel 档案只能用来做“写入”用途。

当 IMEX=1 时为“汇入模式”,这个模式开启的 Excel 档案只能用来做“读取”用途。

当 IMEX=2 时为“连結模式”,这个模式开启的 Excel 档案可同时支援“读取”与“写入”用途。






            //Sql语句
            string strExcel = string.Format("select * from [{0}$]", strSheetName);

            //定义存放的数据表
            DataSet ds = new DataSet();

            //连接数据源
            OleDbConnection conn = new OleDbConnection(strConn);

            try
            {
               conn.Open();
                //适配到数据源
                OleDbDataAdapter adapter = new OleDbDataAdapter(strExcel, strConn);
                adapter.Fill(ds, strSheetName);
            }
            catch (Exception e)
            {
                throw e;
           }
            finally
            {
                conn.Close();
            }
           return ds.Tables[strSheetName];
        }


5.2 datagridview单元格绘制操作。


5.3 listview的读取数据操作。

listViewData.Items.Clear();
listViewData.Columns.Clear();
listViewData.Columns.Add("", 0, HorizontalAlignment.Center);

listViewData.Columns.Add("序号",40, HorizontalAlignment.Right);

listViewData.Columns.Add("快递单号",120, HorizontalAlignment.Center);

listViewData.Columns.Add("修改重量",80, HorizontalAlignment.Right);

var i =0;var strShuju ="";//取得的字符串
IDataObject iData = Clipboard.GetDataObject();

if (iData.GetDataPresent(DataFormats.Text)) { strShuju= (string)iData.GetData(DataFormats.Text); }

if (strShuju.IndexOf("\r\n") == -1)return;

var iShuju = strShuju.Length; //字符串总长度
 while (strShuju != "")

{

    try {

           var myItem =new ListViewItem(); myItem.SubItems.Add((++i).ToString());var strRow = strShuju.Substring(0, strShuju.IndexOf("\r\n"));// 每行字符串
           var iRow = strShuju.Substring(0, strShuju.IndexOf("\r\n")).Length;//每行字符串长度

            var iRow1 = 0; //每行字符串长度
             if (iRow == 0)

             break;

             iRow1 = iRow + 1;

             iRow = iRow + 2;

             iShuju = iShuju - iRow;

             strShuju = strShuju.Substring(iRow, iShuju);

             strRow = strRow + "\t";while (strRow !="") {var strColumn = strRow.Substring(0, strRow.IndexOf("\t"));//每段字符串
             var iColumn = strColumn.Substring(0, strRow.IndexOf("\t")).Length;//每段字符串长度
         

               if (iRow1 == 0) break;

               iRow1 = iRow1 - iColumn -1;

               strRow = strRow.Substring(iColumn +1, iRow1);

               myItem.SubItems.Add(strColumn); }

              listViewData.Items.Add(myItem);

         }

           

        catch (ArgumentOutOfRangeException)

                { break; } }


5.4 listview单元格绘制操作。


6.窗体布局的动态调整, 一般编程时,各个窗体及控件的大小及位置都是固定好了,这样也可以减少程序运行时的负担,即加快运行速度。但对于部分程序,窗体的大小需要根据运行屏幕的尺寸进行改变,这时就需要编码进行动太调整窗体大小了,一般代码如下,当然,窗体中的其它控件也可以进行类似的调整。

            Rectangle rect = Screen.GetWorkingArea(this);//获取屏幕尺寸。
            this.Height = rect.Height;//设置窗体尺寸。
            this.Width = rect.Width;


7.窗体样式的动态调整。如果需要在程序运行时独占屏幕,且不出现状态栏,最大/小化按钮,及关闭按钮等样式,可以进行以下代码编程。

if (this.WindowState == FormWindowState.Maximized)  //判断窗体是否最大化
            {
                this.FormBorderStyle = FormBorderStyle.None;// 窗体的边框及标题栏的状态
            }
            else
            {
                this.FormBorderStyle = FormBorderStyle.None;//
                this.WindowState = FormWindowState.Maximized;//
            }


8. VS平台智能提示异常问题的解决。即从开始->Microsoft Visual Studio 2008->Visual Studio Tools->Visual Studio 2008 命令提示,进入Common7\IDE,然后输入:devenv.exe /setup /resetuserdata /resetsettings或devenv.exe/resetsettings。


9.窗体切换操作代码:Forms f=new Forms();            f.Show();            this.Hide();


10.复杂表格界面的实现。由于VS自带的控件只能实现简单的图表界面,故在实现复杂界面时,如果堆积简单的LABEL,TEXTBOX等控件,则不仅费时,也加重程序运行负担,故需要借用第三方控件, 而大部分简便的控件都是收费的,如水晶报表,DevExpress,NOPI等,但是微软自已的控件dsoframer, 也可以实现类似功能,但操作可能相对复杂,即在调整界面时需要调整控件及EXCEL表格各自的相关属性,以实现项目要求。但dsoframer的使用一般先进行注册,即可以从微软下载后进行本机注册,也可以借助集成的注册程序进行注册。

10.1注册一下DSOFramer.ocx

    操作:将DSOFramer.ocx复制到C:/windows/system32目录下,

     开始->运行->regsvr32 DSOFramer.ocx , 系统会提示DSOFramer.ocx中的DllRegisterServer成功。

10.2添加DSOFramer.ocx到你的项目中,即添加COM组件到VS,即可在工具箱中发现安装成功。一般安装后需要重启,以便顺利使用。

10.3 dsoframer的主要属性, 即ActivationPolicy属性可以设置打开的文件是否处于激活状态;其它表头,边框调整等。

10.4 dsoframer的打开文件事件。即axFramerControl1.Open("文件名");

10.5由于dsoframer打开文件的方式是独占方式,故为了控制文件及时关闭,需要在关闭控件所在窗体时显式关闭该控件。即this.axFramerControl1.Close();


另外,由于该控件是直接打开的EXCEL文件,同时无法设置EXCEL的单元格背景色,故与效果图有些许差别。但相对于单元格错位来说,也基本达标吧。



11.有些项目在屏幕尺寸上有特殊要求,因此,如果开发平台的屏幕尺寸太小,可以在程序中定义一个尺寸基准变量,后续所有的尺寸以此为基础,而在正式提交前,可以更改此变量,从而更改所有的尺寸信息,当然,这也会增加程序启动的负担。



12. C#中是没有所谓的全局变量的.要构造出类的属性作为全局变量。

即可以在Globale类中写:public static string user = ""; //定义变量 user ="abcd";//赋值构造public string User { get { return user ; } set { user =value; }//定义属性。

这样就可以其他窗体访问此User MessageBox.Show (GlobalParams .User); //直接访问. 显示.结果:"abcd"

GlobalParams frm=new GlobalParams (); frm.User="efg"; //修改该静态变量的值 MessageBox.Show (GlobalParams .User); //直接访问. 显示.结果:"efg"


13.另外,在进行操作EXCEL时,注意相关的变量名不要与系统关键字等重复。如某一列的列名不能是password.


14.获得指定文件的目录:Path.GetDirectoryName(str);

15.创建文件。File.Create (String, Int32, FileOptions) 。

如果是创建EXCEL文件。则操作如下。

            Microsoft.Office.Interop.Excel.Application excelApp;//声明创建EXCEL的操作程序的变量,即API。
            excelApp = new Microsoft.Office.Interop.Excel.Application();
            Microsoft.Office.Interop.Excel.Workbook excelBook = excelApp.Workbooks.Add(1);//实际创建EXCEL。
            Microsoft.Office.Interop.Excel.Worksheet excelSheet = (Microsoft.Office.Interop.Excel.Worksheet)excelBook.Worksheets[1];//创建EXCEL中的工作表。
            excelApp.Visible = false;// EXCEL是否可见。
            string path = Path.GetDirectoryName(str);//获取某个文件的目录。
            excelBook.SaveAs(将EXCEL保存为。
            excelSheet.Cells[1, 1] = "username";//给EXCEL标题栏赋值。
            excelSheet.Cells[1, 2] = "pwdword";
            excelSheet.Cells[1, 3] = "status";
            excelSheet.Cells[1, 4] = "classno";
            excelSheet.Cells[1, 5] = "cardno";
            excelSheet.Cells[1, 6] = "loginno";
            excelApp.DisplayAlerts = false;// 是否显示保存对话框。
            excelApp.SaveWorkspace();//将EXCEL内容存储。
            excelApp.Quit();//EXCEL程序退出。


16.SQL中的ExecuteNonQuery()只返回受影响的行数,因此,若进行查询操作,则一直返回0;此时需要进行ExecuteScalar()操作,以判断是否获取到值了。同时,由于SQL是一条记录一条记录地进行查询,因此,ExecuteScalar()返回的是所查询记录的第一个字段。 若需要获取其它字段,需要将记录复制到其他。


17. dataset中数据的访问格式:ds.Tables[0].Rows[0]["字段"]。


18.遍历某个文件夹下的文件方法。

string str=Path.GetDirectoryName(oper.Str);
            DirectoryInfo TheFolder = new DirectoryInfo(str);
           

            foreach (FileInfo NextFile in TheFolder.GetFiles())


19.在以EXCEL存储信息时,需要考虑文件的容量,从而需要考虑在容量不够时新建新的文件,从而引发了数据操作的复杂性。但也无非是多个条件判断而已。


20.C#中怎样取路径中的文件名?

FileInfo fi = new FileInfo("C:\\text.txt");
string strName = fi.Name; // text.txt


21.于C#中操作EXCEL后,关闭对象但EXCEL进程仍然存在的解决办法。设置excelApp.DisplayAlerts = false,就是不提问任何提示,这样再关闭EXCEL对象时,就不会有保存提示,也就不会卡住了.

经试验,此方法不完全正确,需要改进。

在利用SQL进行EXCEL查询,修改,插入,删除等操作时,无需建立EXCEL操作对象,只需建立连接,并及时关闭即可,因此,在此过程中没有多余的EXCEL进程存在的。

但若涉及到EXCEL对象,则需要及时关闭。即(EXCEL对象的名称)appname.quit();即可有效地关闭EXCEL对象及其进程。

若未有效关闭EXCEL进程,则无论系统中含有几个EXCEL进程,则若在程序外打开EXCEL,往往打开两个一样的界面,即原来有一个隐藏的EXCEL显示出来了。


但比较困难的是,若有此操作代码未有效关闭EXCEL进程,刚在后续关闭时较困难。可以手动在系统的进程管理中关闭,也可以在编写更复杂一些的代码进行关闭。















  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值