posts - 11,  comments - 1,  trackbacks - 0
  2008年9月11日

 

很久不写了,原因是自己很懒。本来打算把前段时间在台湾弄的GoogleMap的总结一下。可是那边用的vs2008回来我的电脑装的都是2005,又懒得把程序转化了。呵~
 最近需要几个功能用到了多线程、异步、等等总结一下。会说的一下几个问题:
1、前台UI响应后开个其他的线程干别的。
2、每隔一段时间做点事
3、非UI线程咋访问UI上的控件啊。
4. Timer类原来有好几个啊。


1.这个是我UI的响应一下后要异步的执行一个东东。多线程、异步看的糊里糊涂,看到一句话说的挺好的“异步是目的,多线程是手段”大有拨开云雾见日出的意思。
这里我用的是线程池。将线程安放在线程池里,需使用ThreadPool.QueueUserWorkItem()方法,该方法的原型如下:
//将一个线程放进线程池,该线程的Start()方法将调用WaitCallback代理对象代表的函数
public static bool QueueUserWorkItem(WaitCallback);
//重载的方法如下,参数object将传递给WaitCallback所代表的方法
public static bool QueueUserWorkItem(WaitCallback, object);
注意: ThreadPool类是一个静态类,你不能也不必要生成它的对象。而且一旦使用该方法在线程池中添加了一个项目,那么该项目将是无法取消的。在这里你无需自己建立线程,只需把你要做的工作写成函数,然后作为参数传递给ThreadPool.QueueUserWorkItem()方法就行了,传递的方法就是依靠WaitCallback代理对象,而线程的建立、管理、运行等工作都是由系统自动完成的,你无须考虑那些复杂的细节问题。

代码如下:    
   private void Send()      
  {            
     ThreadPool.QueueUserWorkItem(new WaitCallback(SendRecord));//无参数                      ThreadPool.QueueUserWorkItem(new WaitCallback(SendRecord),"参数");//有参数。      
  }       
  private void SendRecord(object obj)            //定义这个函数的时候必有object的参数       
  {           
   Thread.Sleep(3000);      
  }
调用这个异步执行的时候就用Send(),而真正要干的代码放在SendRecord()里面。


2. 我还需要每隔一段时间干点啥,这里用的是Threading.timer。 
System.Threading.Timer 是一个使用回调方法的计时器,而且由线程池线程服务,简单且对资源要求不高。  
只要在使用 Timer,就必须保留对它的引用。对于任何托管对象,如果没有对 Timer 的引用,计时器会被垃圾回收。
即使 Timer 仍处在活动状态,也会被回收。当不再需要计时器时,请使用 Dispose 方法释放计时器持有的资源。
使用 TimerCallback 委托指定希望 Timer 执行的方法。计时器委托在构造计时器时指定,并且不能更改。此方法不在创建计时器的线程中执行,而是在系统提供的线程池线程中执行。  
Timer timer = new Timer(timerDelegate, s,1000, 1000);

// 第一个参数:指定了TimerCallback 委托,表示要执行的方法;
// 第二个参数:一个包含回调方法要使用的信息的对象,或者为空引用;
// 第三个参数:延迟时间——计时开始的时刻距现在的时间,单位是毫秒,指定为“0”表示立即启动计时器;
// 第四个参数:定时器的时间间隔——计时开始以后,每隔这么长的一段时间,TimerCallback所代表的方法将被
Timer.Change()方法:修改定时器的设置。(这是一个参数类型重载的方法)
代码如下:
public Form1()
        {
            InitializeComponent();
            TimerExampleState s = new TimerExampleState();
            //创建代理对象TimerCallback,该代理将被定时调用
            TimerCallback timerDelegate = new TimerCallback(CheckStatus);
            //创建一个时间间隔为1s的定时器
            System.Threading.Timer timer = new System.Threading.Timer(timerDelegate, s, 1000, 1000);
            s.tmr = timer;
        }
  void CheckStatus(Object state)
        {
            TimerExampleState s = (TimerExampleState)state;
            s.counter++;
            Console.WriteLine("{0} Checking Status {1}.", DateTime.Now.TimeOfDay, s.counter);

            if (s.counter == 5)
            {
                //使用Change方法改变了时间间隔
                (s.tmr).Change(10000, 2000);
                Console.WriteLine("changed");
            }

            if (s.counter == 10)
            {
                //Console.WriteLine("disposing of timer");
                s.tmr.Dispose();
                s.tmr = null;
            }
        }
class TimerExampleState
    {
        public int counter = 0;
        public System.Threading.Timer tmr;
    }
    这个是在form已出现就开始记时了,实际用的时候就在需要的时候创建timer。
当到达调度时刻时,System.Threading.Timer 将异步调用由TimerCallback参数指定的回调方法。也就是说TimerCallback所指向的方法将在.NET Thread Pool中的工作者线程中执行。


3、以前把一个03的程序改成05的时候就遇到了这种问题。这次我没隔一段时执行的代码中有时候会有个反馈到UI上,就又遇到这个问题。看到大家的解决方案主要有:
第一:
Control.CheckForIllegalCrossThreadCalls = false;
线程开始的时候加这么一句,OK,看不到错误了~
啥都能用了~

第二:
用委托,在05里,每个控件都有个InvokeRequired的属性~
判断一下是不是true,是的话进行Invoke操作的,完事了~
但是第一种方法只是简单的将错误提示禁用了,仍然存在跨线程调用控件的问题。为此可能造成两个线程同时或者循环改变该控件的状态导致线程死锁。
Invoke方法是同步的方法,所以执行过程是有先后顺序的,所以就不会出现那个异常了
代码如下:
 //建立个委托
        private delegate void TestDelegate();

        //实际的操作
        private void returnSchool()
        {
            this.textBox1.Text = "xx"+i.ToString();
        }

        //判断一下是不是该用Invoke滴~,不是就直接返回~
        private void returnCB(TestDelegate myDelegate)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(myDelegate);
            }
            else
            {
                myDelegate();
            }
        }
 //在第一个问题的代码里面调用
  private void SendRecord(object obj)
        {
            Thread.Sleep(3000);
            returnCB(returnSchool);
        }
号外:是不是BackgroundWorker可以完成我上述的两个功能呢?DoWork事件,可以把耗时操作绑定到该事件。RunWorkerCompleted事件,当DoWork事件响应函数结束后该事件被触发,并且可以通过事件参数的e.result得到DoWork中设置的e.result。
有时间去想一想。。


4、
关于C#中timer类  在C#里关于定时器类就有3个  
1.定义在System.Windows.Forms里  
2.定义在System.Threading.Timer类里  
3.定义在System.Timers.Timer类里 
System.Windows.Forms.Timer是应用于WinForm中的,它是通过Windows消息机制实现的,类似于VB或Delphi中的Timer控件,内部使用API  SetTimer实现的。它的主要缺点是计时不精确,而且必须有消息循环,Console  Application(控制台应用程序)无法使用。  
 
System.Timers.Timer和System.Threading.Timer非常类似,它们是通过.NET  Thread  Pool实现的,轻量,计时精确,对应用程序、消息没有特别的要求。System.Timers.Timer还可以应用于WinForm,完全取代上面的Timer控件。它们的缺点是不支持直接的拖放,需要手工编码。

System.Timers.Timer定时器不同于System.Windows.Forms.Timer定时器,System.Timers.Timer定时器的定时事件的响应函数并不是在调用定时器Start方法的线程中去执行。

好吧,简单记录一下,又遇到新问题再去研究~~。。。

posted @ 2008-09-11 17:31 风孤鸿 阅读(140) | 评论 (0)编辑
  2008年6月25日

生成excel的时候有时候需要设置单元格的一些属性,可以参考一下:
range.NumberFormatLocal = "@";     //设置单元格格式为文本

range = (Range)worksheet.get_Range("A1", "E1");     //获取Excel多个单元格区域:本例做为Excel表头

range.Merge(0);     //单元格合并动作

worksheet.Cells[1, 1] = "Excel单元格赋值";     //Excel单元格赋值

range.Font.Size = 15;     //设置字体大小

range.Font.Underline=true;     //设置字体是否有下划线

range.Font.Name="黑体";     设置字体的种类

range.HorizontalAlignment=XlHAlign.xlHAlignCenter;     //设置字体在单元格内的对其方式

range.ColumnWidth=15;     //设置单元格的宽度

range.Cells.Interior.Color=System.Drawing.Color.FromArgb(255,204,153).ToArgb();     //设置单元格的背景色

range.Borders.LineStyle=1;     //设置单元格边框的粗细

range.BorderAround(XlLineStyle.xlContinuous,XlBorderWeight.xlThick,XlColorIndex.xlColorIndexAutomatic,System.Drawing.Color.Black.ToArgb());     //给单元格加边框

range.EntireColumn.AutoFit();     //自动调整列宽

Range.HorizontalAlignment= xlCenter;     // 文本水平居中方式

Range.VerticalAlignment= xlCenter     //文本垂直居中方式

Range.WrapText=true;     //文本自动换行

Range.Interior.ColorIndex=39;     //填充颜色为淡紫色

Range.Font.Color=clBlue;     //字体颜色

xlsApp.DisplayAlerts=false;     //保存Excel的时候,不弹出是否保存的窗口直接进行保存

   workbook.SaveCopyAs(temp);/**////填入完信息之后另存到路径及文件名字

posted @ 2008-06-25 23:32 风孤鸿 阅读(335) | 评论 (1)编辑
  2008年6月24日
今天遇到了进入不了断点的问题,后发现是pc与ppc上cf版本不同导致。具体见:
http://www.cncvs.com/html/bencandy.php?fid=5&aid=22
ppc上的注册表查看可以用vs2005的remotetools之间看到,当然得两个机子要activesyec连接~。。。
posted @ 2008-06-24 22:39 风孤鸿 阅读(104) | 评论 (0)编辑

一直在想,dotnetbar中有了tabcontrol了为啥还有个tabstrip,不知道用在那里.今天想到,可以用作MDI子窗体的标签.效果图如下:
具体实现代码参照了博克园中一篇帖子,做了小小改动.
http://www.cnblogs.com/maxianghui/archive/2006/10/26/540869.html
有兴趣的可以参考下
posted @ 2008-06-24 00:46 风孤鸿 阅读(249) | 评论 (0)编辑
  2008年6月15日
 原来是这么写的,可以看出provincetemp.GetModel(idofprovince)是model里面得到一个对象,有数据库操作.但是经过这一句后跳到provinceList.Add(provincetemp);
时发现datareader已经isclosed==true了,以前没有遇到过.在一个函数里面reader就没有问题,但是在while里面如果会跳到另一个文件,再跳回来就close了?不知道是所有datareader的问题,还是mysql的有问题?

MySqlDataReader readerProvince = DbOperate.getDataReader(sql);
            while (readerProvince.Read())
            {
               int idofprovince =Convert.ToInt32(readerProvince["idofprovince"]);
                province provincetemp = new province(); ;
                provincetemp.GetModel(idofprovince);
                provinceList.Add(provincetemp);
            }

后来改成下面就没有问题了.......
            DataSet ds=DbOperate.getDataSet(sql);
            for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
            {
                int idofprovince = Convert.ToInt32(ds.Tables[0].Rows[i]["idofprovince"]);
                province provincetemp = new province(); ;
                provincetemp.GetModel(idofprovince);
                provinceList.Add(provincetemp);
            }
posted @ 2008-06-15 02:00 风孤鸿 阅读(45) | 评论 (0)编辑
  2008年6月6日
最近在使用dotnetbar,简单写一下使用方法,具体细节有待研究。希望对初次使用的人有用。
1、Bar就是一个菜单栏,可以右键增加button和combobox等等许多,大家可以一一试试。
2、bubbleBar是一个工具栏,右键增加button(可以增减tab但是没看出啥效果),然后就可以实现苹果系统的波浪选择效果。
3、balloonTip,气球。把他拖到任何一个控件上面,当鼠标在上面悬浮时就出现气球。
4、ContextMenuBar,这是在鼠标右击的时候出来的菜单.
5、colorPickerButton控件,用来做颜色的选择。
6、ComboBoxEx,看名字就知道了
7、ListViewEx和GroupPanel,看名字就知道是什么了。好看了许多
8、RibbonBar,还是button,office2007风格,可以右键增加。
9、explorerBar,类似于winxp左边的导航菜单,在vista大行其道的今天,觉得不是十分漂亮了
10、itemPanel,与expandableSplitter结合可以做导航栏,设置ExpandedControl属性,鼠标过度效果
11、expandablePanel,可下拉的控件,点击后回缩
12、maskedTextBoxAdv,textbox,加了个按钮实现清空
13、tabControl,这个比较有用一点。
先写这么点,没有涉及到具体应用,希望给第一次用的人不知道是什么了查一下。
posted @ 2008-06-06 17:24 风孤鸿 阅读(231) | 评论 (0)编辑
  2008年5月22日
前一段时间需要比较时间,本来想DateTime.Compare( dt1, dt2 ),但是为了方便我得到的数值是string的,还得和当前时间进行比较,比如我写12:00:00,如果Convert.ToDateTime后是带有年月日而且全是零!!。后来想我只是比较时刻或者说shortDateTime,所以换了一种思路比较时刻。
例子:比较是上午还是下午。
           TimeSpan minDay = new TimeSpan(12, 0, 0);//定义一个中午时间
           TimeSpan time2 = TimeSpan.Zero;//
           TimeSpan.TryParse(time, out time2);//time是string的时间,把它转换成timespan的
           if (time2 != TimeSpan.Zero)
           if (time2.CompareTo(minDay) < 0)//上午
posted @ 2008-05-22 22:03 风孤鸿 阅读(239) | 评论 (0)编辑
  2008年5月13日
以前看过,没怎么用,最近用到的东西。
哈希表和哈希函数
对于动态查找表而言,1) 表长不确定;2)在设计查找表时,只知道关键字所属范围,而不知道确切的关键字。因此,一般情况需建立一个函数关系,以f(key)作为关键字为key的录在表中的位置,通常称这个函数f(key)为哈希函数。(注意:这个函数并不一定是数学函数)
哈希函数是一个映象,即:将关键字的集合映射到某个地址集合上,它的设置很灵活,只要这个地址集合的大小不超出允许范围即可。
现实中哈希函数是需要构造的,并且构造的好才能使用的好。
多表联查,左外连接,右外连接,全连接
posted @ 2008-05-13 15:23 风孤鸿 阅读(27) | 评论 (0)编辑
  2008年3月31日
问题1:在派生类中命名了同名的属性或者方法,会显示有问题,但是会编译成功?而且貌似默认成是new了,

 class Program
    {
        static void Main(string[] args)
        {
            contact [] contacts=new contact [2];
             contacts[0]=new class1();
             contacts[1]=new class2();
             class2 c2 = new class2();
             class1 c1 = new class1();
             contacts[0].A = "1";
             Console.WriteLine(c1.A);
             foreach(contact ct in contacts)
             {
                   //ct.A = "9";

                   Console.WriteLine(ct.prinf());
                   Console.WriteLine(ct.A);
                   Console.WriteLine(c2.prinf());
              }

        }
    }
    abstract public class contact
    {
        public virtual string prinf()
        {
            return ("这是虚方法");
        }
        string a="0";

        public virtual string A
        {
            get { return a; }
            set { a = value; }
        }
    }

    public class class1 : contact
    {
        public override string prinf()
        {
            return ("这是新的方法");
        }
        string a="6";
        public  string A
        {
            get { return a; }
            set { a = value; }
        }
    }
    public class class2 : contact
    {
        public new string prinf()
        {
            return ("这是另一个新的方法");
        }
    }


显示:
6
这是新的方法
1
这是另一个新的方法
这是虚方法   // 这里没有重载prinf();
0
这是另一个新的方法。
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
问题2:
后来看书,多态性。
Animal myanimal=mycow();相当于是把某基本类型的变量赋予其派生类变量(这句话真绕,我的理解是派生类=》给基类)而myanimal调用基类方法相当于从派生类中调用这个方法,但他不能调用只在派生类中定义的方法。我的理解是,即使把派生类的变量给了基类变量,但是归根到底myanimal是基类变量,所以不能用只在派生类中才有的东西。如果要用需要类型转换。
对于上面代码。contacts[1]是基类即使给了new class2,也不能调用他的prinf。
而对于class1中的属性A,似乎也是new的了。
contacts[0].A相当于重载基类的A。即如果去掉contacts[0].A = "1";则也会输出contacts[0].A = "0";
posted @ 2008-03-31 16:06 风孤鸿 阅读(7) | 评论 (0)编辑
  2008年3月24日

     最近没有项目,所以最近看书没有太关注技术细节的学习,比较有时间所以看看了一些思想性的东西.模式啦架构啦等等准备一点点学习.每天强迫自己学一点,然后作一点记录.
    今天说一点写代码习惯的问题.一个有经验的程序员手下的代码也有其艺术性.结合最近自己看书记录如下:
    1,少复制,多复用. 同一功能代码尽量封装.想到年自己做一个程序,对几种不同设备做一样的分析,居然全是复制,结果一处更改,全都得改,做了很多无用功.还有当时不懂反射,不知道策略模式,充满大量if else.呵呵.
    2,过长的函数.Juval Lowy的C#编码规范中说,一个函数代码不要超过50行.(<.NET组件程序设计>电工出版社).应该按功能分解函数.
    3,过大的类,这个问题似乎和上面相似.应该按职责分成独立类,多用继承,公共方法放在基类.
    4,过长参数.说一个函数不要超过5个参数,似乎如果相关参数很多,封装成一个对象,传递对象好些.
    5,降低类的耦合,减轻代码地震.
    6,基于接口编程是个好习惯.
    7,滥用技巧.这个似乎对于我们这样的新手比较多见,学到新东西迫不及待要用上.前段时间做一个小东西,才几张表没太多数据库操作,我居然要用Nhibernate,现在想想这个过程确实加强了自己对nhibernated 学习,但是对程序来说没什么必要.
    8,多态集合滥用.把集合元素设为Object,降低可读性.多用泛型集合.泛型还没有学好,这是下一步目标.
    9,不要全public,隐私权在代码中也很重要.
    10,多用属性代替共有字段.至于好处是什么我的实践中没发现,似乎成了习惯.网上搜下说什么字段拦截,还不懂.
    11,命名规范.自己命名变量时总喜欢用一些无意义的字母,这很不好.应多用英文.(可怜我英文)说到这还有数据库中字段命名也要规范,前段时间给人做一个东西,表的字段命名非要我用拼音说英文他们公司员工看不懂,我也很无奈....
    oK,其实就是个读书笔记.希望自己以后养成好习惯.还有希望自己每天学一点的计划能坚持.

posted @ 2008-03-24 00:36 风孤鸿 阅读(51) | 评论 (0)编辑