天天看點

C#使用Tips(部分)

文法要點

一些基本的程式設計範式

  • 類名盡量有具體的實際意義
  • 類名每個單詞首字母大寫
  • 類中成員變量首字母小寫,之後的單詞的首字母大寫,如

    alarmClock

  • 類中方法變量每個單詞首字母大寫,如

    GetPulse()

  • 結構體定義之前加上S,接口定義之前加上I
  • 使用

    / /

    注釋,不使用 注釋
  • 全局變量定義之前加上g

關于類的權限問題的說明

  • 一般情況下,優先使用protected、其次使用private,最後使用public
  • 當類可能需要被繼承時,優先考慮protected;當類不太有可能需要被繼承時,優先考慮private
  • 定義類的名稱時,一定要先考慮好它的作用以及相應的方法

泛型程式設計

  • 引入背景
    • 為了說明方法所有可能的資料類型而需要覆寫某種方法或者某種方法集合的時候,會發生代碼膨脹
    • 為解決這個問題,引入泛型程式設計的概念
  • 代碼如下
    • 函數定義如下
      static void SwapTwoNum<T>(ref T val1, ref T val2)
      {
          T swap;
          swap = val1;
          val1 = val2;
          val2 = swap;
      }
                 
    • 在在函數中調用如下
      int a = 1, b = 2;
      double c = 1.0, d = 2.0;
      SwapTwoNum<int>(ref a,ref b);
      SwapTwoNum<double>(ref c, ref d);
                 
      可以實作對a,b和c,d的值的交換(此處使用引用類型直接改變變量的值)不用對函數進行覆寫,直接改變函數後T的類型即可
  • 注:泛型不能對2個不同的資料類型進行操作,比如若要定義

    Swap<T1,T2>(ref T1 val1 , ref T2 val2)

    則在運作時會出錯。

Static的說明:

  • 函數中的static表示該變量隻在第一次進入該函數時會賦給一個初值,以後進入時直接調用上次的值
  • 類中靜态成員表示不需要執行個體化就可以直接檢視該成員資訊,調用方法是:”類名.成員名”。如果不加static關鍵字,則需要在執行個體化類之後,再在具體的類之後調用該成員資訊

繼承:

  • 子類可以繼承基類的除私有以外的所有成員和方法,想重寫基類的方法時,需要首先在基類中用virtual聲明方法,再在子類中用override(覆寫)關鍵字聲明該方法

接口(Interface)

注意的問題

  • 接口不能包含常量、字段、運算符、執行個體構造函數、析構函數或類型、不能包含靜态成員。
  • 接口成員是自動公開的,且不能包含任何通路修飾符。
  • 接口自身可從多個接口繼承,類和結構可繼承多個接口,但接口不能繼承類。

包括顯式接口和隐式接口

  • 隐式接口
    • 如下例,

      void ImplicitBark();

      是隐式接口,類繼承該接口時,需要重新定義該接口

      public void ImplicitBark()

    • 關于調用隐式接口的方法
      • way 1
        IBark ie = new InterfaceExample();
        ie.ImplicitBark();
                   
      • way 2
        InterfaceExample ie = new InterfaceExample();
        ie.ImplicitBark();
                   
  • 顯式接口
    • 需要通過

      void IBark.ExplicitBark()

      來定義該方法,而且不能用public、protected、private等定義
    • 顯示接口的定義方法
      • way 1
        IBark ie = new InterfaceExample();
        ie.ExplicitBark();
                   
      • 注:隐式接口的第二種方法在此處不适用,否則會報錯。若是想用,需要進行強制類型轉換
        InterfaceExample ie = new InterfaceExample();
        ((IBark)ie).ExplicitBark();
                   
  • 代碼
    • 類和接口定義
      public interface IBark
      {
          void ImplicitBark();
          void ExplicitBark();
      }
      public class InterfaceExample : IBark
      {
          public InterfaceExample()
          {
          }
      
          public void ImplicitBark()
          {
              Console.WriteLine(" this is ImplicitBark ");
          }
      
          void IBark.ExplicitBark()
          {
              Console.WriteLine(" this is ExplicitBark ");
          }
      }
                 
    • main.c
      IBark ie = new InterfaceExample();
      ie.ImplicitBark();
      ie.ExplicitBark();
                 

隐式接口存在的意義

  • 一般情況,當類或者結構要實作的是單個接口,可以使用隐式實作。
  • 如果類或者結構繼承了多個接口且接口中具有相同名稱成員時,就要用到顯式實作,當顯式實作方式存在時,隐式實作方式就失效了。

系統中常用的靜态類

  • Math
  • DateTime
  • Random

字元串相關說明

  • StringBuilder比String操作要快得多
  • 可以通過格式化控制符進行輸出,比如說工資、時間等變量,可以輸出為固定的格式,用法為String.Format….

數組

一維數組

定義

  • 資料類型[ ] 數組名
    • int[] a;

初始化

  • 靜态初始化
    • 将所有的元素初始值列舉出來
    • string[] b ={ "籃球", "足球", "排球", "網球", "羽毛球", "乒乓球" };

  • 動态初始化
    • 先固定數組大小,沒有賦初始值
    • int[] a = new int[10];

周遊通路數組

  • foreach
    • foreach(類型 辨別符 in array)
    • foreach(int i in ArrayA)

二維數組

定義

  • int[ , ] a;

初始化

  • 靜态
    • int[ , ] a ={ { 3, 5, 7 }, { 2, 4, 6 }, { 9, 5, 1 } };

  • 動态
    • float[ , ] score = new float[7,5];

鋸齒狀數組

  • int [][] a = new int[12][];

    ,該二維數組的每一行的元素個數都可以不相同

建立數組的靜态方法

  • Array arr = Array.CreateInstance(Type type, int[]length, int[]lowbound);

  • 隻能用SetValue和GetValue擷取或者對數組進行指派

數組的基本屬性

  • Length:長度
  • Rank:次元
  • Clone:複制
    • b = (int[])a.Clone();

      :将a複制到b中
    • 複制之後b的長度被改變,建立一個關于a的淺表副本
    • 改變b的值,不改變a的值,即目标數組和源數組是獨立的
  • CopyTo:複制
    • a.CopyTo(b,2);

      :将a複制到b中,b從b[2]開始改變
    • 注意要使數組下标符合要求
    • 這樣指派之後改變b,不會對a造成影響,即a和b是獨立的
  • 關于複制還有一種方法
    • 代碼
      int[] a = { 1, 2, 3, 4, 5, 6, 7 };
      int[] b = a;
                 
    • 相當于建立一個關于a的引用,之後改變b中元素的值,a中元素的值也會跟着改變

利用程式運作時間間接測量算法複雜度

  • 用DateTime類相減是不準的,因為.NET中還有線程處理以及無用單元收集等其他事情需要處理,測得的時間會和算法複雜度運作時間相差很多
  • 常用以下方法測量算法運作時間(不考慮編譯器處理其他事情消耗的時間)
    TimeSpan duration;
    /*algorithm you want to check should be placed here*/
    //...
    /*end of you algorithm*/
    duration = Process.GetCurrentProcess().TotalProcessorTime;
    Console.WriteLine(duration.TotalSeconds);
               

資料結構

基礎的排序算法

  • 冒泡排序
  • 選擇排序
  • 插入排序

基礎的查找算法

  • 順序查找
  • 二叉查找
  • 遞歸的二叉查找算法

棧(Stack)

采用LIFO(先入後出)的結構,主要應用如下

算術運算

進制轉換

  • 進制轉換函數
    //将10進制的數num轉化為b進制的數,将轉化後的數以棧的形式傳回
    //棧的頂部是最高位,底部是最低位
    static Stack HexConversion(int num, int b)
    {
        Stack digits = new Stack();
        do
        {
            digits.Push(num % b);
            num /= b;
        }while( num != 0 );
        return digits;
    }
               
  • 觀察結果的代碼如下
    Stack stack4Three = new Stack();
    stack4Three = HexConversion(100,8); //将100的10進制轉化為8進制
    while (stack4Three.Count > 0)
    {
        Console.Write(stack4Three.Pop());
    }
    Console.WriteLine();
               

隊列(Queue)

常用元件

ImageList

  • 可以将一組圖檔加入到該集合中,之後可以通過下标去通路該圖檔集合
  • 可以用來顯示動畫(先将一組圖檔放在集合中,再循環顯示即可)

Timer

  • 可以實作固定的時間間隔執行某段程式,相當于定時中斷
  • 常用于定時重新整理界面等,如果時間顯示

菜單

MenuStrip

ToolStrip

對話框

檔案選擇對話框

檔案操作

檔案

這裡主要是對檔案進行複制、删除、移動、建立等操作

  • File
    • 靜态類,不需要執行個體化
  • FileInfo
    • 必須被執行個體化才能使用

檔案夾

  • Directory
    • 靜态類,不需要執行個體化
  • DirectoryInfo
    • 必須被執行個體化才能使用

檔案讀寫

引入流的概念,對檔案讀或寫

  • 位元組序列化的抽象概念,串行化裝置的抽象表示
  • 留得基本操作
    • Read
    • Write
    • Seek:查找(網絡流一般不支援查找)

建立檔案流的方法

  • FileStream類
  • 寫入檔案時,需要将字元串轉換為位元組數組,實作方法如下
    string a = "123";
    ASCIIEncoding b = new ASCIIEncoding();
    byte[] c = b.GetBytes(a); //
               
    之後就可以将位元組數組c寫入檔案中,如果此時a字元串是中文字元,則轉換的過程中會出現資訊丢失的現象(隻保留低8位)

GDI圖形圖像處理相關

坐标系的概念

GDI有3種坐标系

  • 世界坐标系
  • 裝置坐标系
  • 頁面坐标系

圖形繪制相關技巧

錯誤的嘗試

  • 在視窗中繪制好圖像後,改變視窗大小或者最小化、最大化等操作時,繪制的圖像會“消失”,要想使圖像資訊不丢失,需要在視窗中添加Paint事件,每次繪制時,需要重新繪制該圖像
    private void CClockExercise_Paint(object sender, PaintEventArgs e)
    {
        Graphics Pic = CPbDispGraph.CreateGraphics();
        Pen MyPen = new Pen(Color.Red);
        Pic.DrawEllipse(MyPen
                        , 0, 0
                        , CPbDispGraph.Width - 1, CPbDispGraph.Height - 1);
        Pic.DrawLine(MyPen
                , new Point(0, 0)
                , new Point(CPbDispGraph.Width - 1, CPbDispGraph.Height - 1));
        Pic.Dispose();
    }
               
    注:這種方法實作重繪時,速度比較慢,有時改變控件大小後,需要較長時間才能看到改變後的效果。
  • 慢的原因
    • 在Form的重繪函數中想要重繪PictureBox的視窗,速度就慢下來了,要想加快速度,需要直接在需要重繪的視窗中調用該視窗的重繪函數
  • 改進後的代碼如下:
    private void CPbDispGraph_Paint(object sender, PaintEventArgs e)
    {
        Graphics g = e.Graphics;
        PointF[] pt = new PointF[360]; //定義點數組
        using (Pen pen = new Pen(Color.Black)) //定義畫筆
        {
            for (int i = 0; i < 720; i += 2) //計算獲得曲線上每個點的坐标
            {
                pt[i / 2].X = i / 2;
                pt[i / 2].Y = (float)(60 - 50 * Math.Sin(Math.PI / 180 * i));
            }
            g.DrawLine(pen, 0, 60, 400, 60); //繪制一條表示數軸的直線
            g.DrawCurve(pen, pt); //繪制基數樣條構成的正弦曲線
        }
    }
               
    這段代碼是PictureBox的重繪函數

描述坐标系的基本結構

  • Point和PointF
  • Size和SizeF
  • Rectangle和RectangleF

基本的GDI對象

  • 畫筆(Pen)
  • 筆刷(Brush)

關于圖像雙緩沖的說明

  • 圖像顯示時,會涉及到重新整理的問題,視窗上控件太多或者重新整理速度太快時,往往會出現圖像閃爍的問題,因為程式一直在重新整理;而如果等使用者畫完之後再輸出就不會出現這種情況。
  • solution:建立一個Bitmap的畫布,将所有的東西先畫到畫布上,再将畫布一次性加載到視窗中,可以避免螢幕閃爍的情況
  • 代碼
    Bitmap bmpBuffer = new Bitmap(CPbRealTimePlot.Width , CPbRealTimePlot.Height);
    Graphics g = Graphics.FromImage(bmpBuffer);
    //以下的Using表明pen的作用域,當這段代碼執行結束之後,會釋放pen資源
    using (Pen pen = new Pen(Color.Blue)) //定義畫筆
    {
        //資料平移與計算
        for (int i = 0; i < NUM_TO_DISP-1; i++)
        {
            ptForRealTimeDisp[i].Y = ptForRealTimeDisp[i + 1].Y; 
        }
        ptForRealTimeDisp[NUM_TO_DISP-1].Y = 50 + 50 * (float)Math.Sin(2*Math.PI* numForSinPlot/NUM_TO_DISP);
        numForSinPlot++;
        if (numForSinPlot == NUM_TO_DISP)
            numForSinPlot = 0;
        //繪圖
        g.Clear(Color.White); // 首先清除圖像,再進行繪制
        g.DrawLine(pen, 0, 50, 400, 50); //繪制一條表示數軸的直線
        g.DrawCurve(pen, ptForRealTimeDisp); //繪制基數樣條構成的正弦曲線
    }
    //下面這段代碼将Bitmap資源釋放到視窗中并顯示
    using (Graphics tg = CPbRealTimePlot.CreateGraphics())
    {
        tg.DrawImage(bmpBuffer, 0, 0);
    }
               

函數或者方法資料傳遞的差別

連結網址

值傳遞

  • 在通過值傳遞作為方法參數的變量時,傳遞給方法的是資料副本。在方法中對該資料的任何修改都不會對初始值有任何影響。
    static void DoSomething(int parameter)  
               

引用傳遞

  • 如果傳遞引用的話,那麼無論在程式的什麼地方作改變的話(可能是在另一個方法、屬性中,甚至是另一個對象中),都會改變使用改引用的值。對方法中任何參數的改變都将影響方法的傳回值。
    static void DoSomething(ref int parameter)
               

值傳遞引用類型

  • 傳遞的是對象的引用
    static void DoSomething(Person somePerson)
               
    • 如果按照如下方法,則不會修改主程式中somePerson的一些屬性
      static void DoSomething(Person somePerson)  
      {  
          somePeron=new Person(100);  //建立一個新對象,指派會不起作用
      }  
                 
    • 如果按照以下方法,則會修改主程式中somePerson的一些屬性
      static void DoSomething(Person somePerson)  
      {  
          somePerson.Age=100;   //這個對象相當于一個引用,直接改變其屬性即可
      } 
                 

some other tips

獲得伺服器的運作時間

  • Environment.TickCount

    :以毫秒為機關 ,一般對應開機時間

視窗大小改變時,視窗内控件大小也相應發生改變

  • 為視窗添加ResizeBegin事件
    private void CClockExercise_ResizeBegin(object sender, EventArgs e)
    {
        BeforeSize = this.Size;//擷取之前的視窗大小
    }
               
  • 為視窗添加ResizeEnd事件
    private void CClockExercise_ResizeEnd(object sender, EventArgs e)
    {
        Size EndSize = this.Size;
        float percentWidth;
        float percentHeight;
        //獲得變化比例
        percentWidth = (float)EndSize.Width / BeforeSize.Width;
        percentHeight = (float)EndSize.Height / BeforeSize.Height;
    
        ChangeAllSzie(this,percentWidth,percentHeight);//調用遞歸函數,改變控件的大小
    }
               
  • 其中,上面的ChangeAllSzie函數是遞歸的,描述如下
    private void ChangeAllSzie(Control control , float percentWidth , float percentHeight)
    {
        foreach (Control ctrl in control.Controls)
        {
            //按比例改變控件大小
            ctrl.Width = (int)(ctrl.Width * percentWidth);
            ctrl.Height = (int)(ctrl.Height * percentHeight);
            //為了不使控件之間覆寫 位置也要按比例變化
            ctrl.Left = (int)(ctrl.Left * percentWidth);
            ctrl.Top = (int)(ctrl.Top * percentHeight);
            if (ctrl.HasChildren)//如果容器中還有子容器,則進行遞歸
            {
                ChangeAllSzie(ctrl, percentWidth, percentHeight);
            }
        }
    }
               
  • 注意
    • 此時,視窗的FormBorderStyle屬性一定要設定為Sizable
    • 當最大化或者最小化視窗時,控件大小不發生改變,隻有拖動視窗改變其大小時,控件大小才相應随之改變

關于添加事件後,删除事件對應代碼,程式運作出錯的說明

  • 在輕按兩下添加事件後,VS做了
    • 添加事件響應代碼
    • 在”視窗名.Designer.cs”中添加了

      this.button1.Click += new System.EventHandler(this.button1_Click);

      ,這通常在

      #region Windows 窗體設計器生成的代碼

      中隐藏,需要将其展開
  • 如果需要删除對應的事件響應,需要同時删除以上2處才可以

執行CMD指令

  • 包含命名空間
    • using System.Diagnostics;

  • 調用

    Process.Start("CMD.Exe");

    ,或者其他指令也可以

CLR(Common Language Runtime)

  • 定義:公用語言運作時
  • 相當于一個運作環境,C#先編譯成中間語言,再在CLR上面執行

Dispose資源釋放相關

資源

在CLR出來之後,Windows系統資源開始分為“非托管資源”和“托管資源”。

  • 非托管資源是
    • 所有的Window核心對象(句柄)都是非托管資源,如對于Stream,資料庫連接配接,GDI+的相關對象,還有Com對象等等,這些資源并不是受到CLR管理;
    • 需要顯式釋放的,也即需要你寫代碼釋放
  • 托管資源是
    • 由CLR管理配置設定和釋放的資源,即由CLR裡new出來的對象。
    • 并不需要顯式釋放,但是如果引用類型本身含有非托管資源,則需要進行現實釋放

釋放規則

  • 建立視窗等資源時,因為受系統管制,資源回收速度較快,是以不需要Dispose回收
  • GDI繪圖中,如果建立畫筆、筆刷、圖像等對象時,因為比較占用系統資源,是以在函數執行結束,即繪圖完成時,需要将其釋放,用pen.Dispose()即可。或者采用以下方法:
    using (Pen pen = new Pen(Color.Black)) //定義畫筆
    {
        for (int i = 0; i < 720; i += 2) //計算獲得曲線上每個點的坐标
        {
            pt[i / 2].X = i / 2;
            pt[i / 2].Y = (float)(60 - 50 * Math.Sin(Math.PI / 180 * i));
        }
        g.DrawLine(pen, 0, 60, 400, 60); //繪制一條表示數軸的直線
        g.DrawCurve(pen, pt); //繪制基數樣條構成的正弦曲線
    }
               
    這是确定了Pen的生命周期,即這段代碼執行完之後,Pen資源就會被系統釋放。

因為重繪圖像時,圖像是作為參數傳進來的,在結束時,不需要Dispose圖像,直接由系統控制其生命周期就行。

關于TextBox限制數字輸入的問題

  • 為TextBox添加KeyPress的事件,代碼如下
    private void CTbSecondSet_KeyPress(object sender, KeyPressEventArgs e)
    {
        if ((!Char.IsNumber(e.KeyChar))
         && (e.KeyChar != (char)8)) //判斷按下的字元是數字或者倒退,若都不是,則提示使用者輸入數字
        {
            e.Handled = true;
            MessageBox.Show("請輸入數字");
        }
        else
        {
            e.Handled = false;
        }
    }
               
  • 如需要對數字判斷大小,看是否在合理範圍内,則需要通過給TextBox添加Leave事件,代碼如下
    private void CTbHourSet_Leave(object sender, EventArgs e)
    {
        if (CTbHourSet.Text.Equals(""))
            CTbHourSet.Text = "0";
        if (Convert.ToInt32(CTbHourSet.Text) < 0
          || Convert.ToInt32(CTbHourSet.Text) >= 24)
        {
            CTbHourSet.Clear();
            MessageBox.Show("請輸入有效的時間範圍");
        }
    }
               

擷取滑鼠在螢幕上的位置

電腦螢幕

  • Point pt = MousePosition;

    ,得到滑鼠的值,可以通過

    pt.X

    pt.Y

    得到其X、Y的坐标值,原點是電腦螢幕左上角
  • Point pt2= this.PointToClient(pt);

    ,獲得滑鼠在窗體上的坐标值,即以窗體的原點為螢幕原點,對pt進行整體平移

關于在工程中考慮問題的一些方法

原諒我還沒想好标題

  • 對于比較的問題,比如說鬧鐘到達時間就觸發某一事件,則觸發條件需要設定得盡量嚴苛。不能是簡單地對時間進行比較就結束,而是應該記錄上次的時間,當目前時間大于等于鬧鐘時間且上次時間小于鬧鐘時間時,觸發鬧鐘響應事件。即用線與點進行比較。這是因為windows的系統時間為了和網絡時間進行校準,有時會發生跳變,有可能恰好跳過鬧鐘時間,此時就需要采用該種方法對鬧鐘時間進行判斷。
    • 在實時資料采集處理過程中,這種“點對線”的思想十分常用,因為離散控制系統中,資料很容易發生跳變,涉及比較時,采用這種思想可靠性會更高。

代碼異常處理

  • 在寫代碼時,一定要考慮到各種可能出現的條件,盡可能分情況讨論并給使用者提示以便于解決問題,盡可能不用

    try...catch...

    抛出異常。

名額的關系

  • 每個設計任務的名額都是有其一定的背景的,不要認為名額看起來沒有什麼用就不去管它,否則可能會丢掉很多細節

WPF操作相關

使用dll或者外部庫

  • 在“解決方案”裡右擊“引用”,添加dll的引用;
  • 在toolbox裡右擊,單擊“選擇項”,在wpf元件中選擇“浏覽”,選中加載的dll,即可在“所有WPF元件”中找到新加的控件了

Silverlight使用相關

安裝

  • 尼瑪,這個花了我2天!!!
  • 安裝需要版相同的tools和SDK,我當時就是安裝了不同版本的,是以程式可以運作但是設計器中觀察不了,安裝tools時,其實就将runtime也安裝了(包含在裡面)
  • VS2010來說,最好使用3.0或者4.0版本的Siverlight,因為如果要用5.0版本的,需要安裝VS更新檔包,比較麻煩。
  • 先安裝SDK,再安裝tools

sharepoint相關

在sharepoint中插入webpart部件

有以下幾種方法

* 直接建立webpart然後插入xap檔案an,不過對于xap的url位址,我不是特别清楚,也沒有嘗試成功

* 先将silverlight産生的xap檔案儲存在sharepoint的文檔庫中,此時xap檔案的url位址更加友善一點,找到那個文檔,右擊複制連結即可

關于實習的過程中silverlight、WPF、WCF通訊相關的問題

通訊簡介

  • 實習的工程項目是BS架構,通訊采用的是用戶端對象模型,是以需要在本地實時地擷取sharepoint資料,通過VS導入sharepoint資料。
  • 關于通訊,WPF和sharepoint通訊是利用的同步通訊,即而silverlight作為webpart,在網頁中進行相關操作時利用的異步通訊,是以在此過程中需要利用異步程式設計方法。
  • 關于webpart的引入檔案,即xap檔案的放置問題,如果放在本地(伺服器需要能夠與通路到本地路徑才可),網頁相關的緩存可能會使剛剛在檔案目錄裡更新的檔案得不到及時的引用,即浏覽器直接引用浏覽器之前的緩存了;是以,選擇xap檔案放在sharepoint的文檔庫中,這樣因為sharepoint的安全保護問題,會使浏覽器對該網頁的緩存無效,即每次引入時都是最新的文檔,可以保證網頁的實時重新整理

WPF操作過程中的資料的增删改查相關問題

準備工作

  • 在資料源中添加sharepoint資料,需要填寫添加網頁的網址,VS會自動生成基于sharepoint的引用以及相關的命名空間等。

相關代碼

  • 初始化
    private CStopCondition stopCondition = new CStopCondition();
    private ProTest.溫升實驗DataContext dc = null; //重點!之後都是對這個對象進行操作
               
  • 資料連接配接服務
    private bool IsConnect( )
    {
        try
        {
            dc = new ProTest.溫升實驗DataContext(
                    new Uri("http://win-ubfvccleemg/sites/ProTest/_vti_bin/ListData.svc/"));//存儲資料的網址
            //dc.Credentials = CredentialCache.DefaultCredentials;
            NetworkCredential nc = new NetworkCredential("jiang", "qwer1234-");//帳号和密碼
            dc.Credentials = nc;
            return true;
        }
        catch
        {
            return false;
        }
    }
               
  • 增加資料項
    private bool AddData(CStopCondition cSc)
    {
        if (dc.停止條件清單.Where(c => c.名字 == cSc.name).FirstOrDefault() == null)
        {
            ProTest.停止條件清單Item pt = new ProTest.停止條件清單Item();
            pt.名字 = cSc.name;
            pt.資料 = cSc.Serialize();
            pt.标準 = cSc.referCriterion;
            pt.描述 = cSc.description;
            pt.參數 = cSc.parameters;
            pt.種類 = cSc.kind.ToString();
            dc.AddTo停止條件清單(pt);
            dc.SaveChanges();
            return true;
        }
        else
        {
            return false;
        }
    }
               
  • 修改資料項
    private bool ChangeData()
    {
        int num = dc.停止條件清單.Where(c => c.名字 == stopCondition.name).Count();
        if (num >= 1 && (nameOld != stopCondition.name))
        {
            return false;
        }
        else
        {
            var item = dc.停止條件清單.Where(c => c.名字 == nameOld).FirstOrDefault();
            item.名字 = stopCondition.name;
            item.資料 = stopCondition.Serialize();
            item.标準 = stopCondition.referCriterion;
            item.描述 = stopCondition.description;
            item.參數 = stopCondition.parameters;
            item.種類 = stopCondition.kind.ToString();
            dc.UpdateObject(item);
            dc.SaveChanges();
            return true;
        }
    }
               
  • 查詢資料項
    private bool QueryData(string name)
    {
        if (dc.停止條件清單.Where(c => c.名字 == name).FirstOrDefault() != null)
        {
            var results = (from item in dc.停止條件清單
                           where item.名字 == name
                           select new
                           {
                               data = item.資料
                           });
            string str = "";
            foreach (var res in results)
            {
                str += res.data;
            }
            MessageBox.Show(str);
            return true;
        }
        else
        {
            return false;
        }
    }
               
  • 删除資料項
    private bool DeleteData(string name)
    {
        if (dc.停止條件清單.Where(c => c.名字 == name).FirstOrDefault() != null)
        {
            dc.DeleteObject(dc.停止條件清單.Where(c => c.名字 == name).FirstOrDefault());
            dc.SaveChanges();
            return true;
        }
        else
        {
            return false;
        }
    }
               

silverlight操作sharepoint資料以及将xap部署到sharepoint的webpart中去的問題

網頁部署相關問題

  • silverlight工程生成解決方案後會在

    SilverlightApplication1\SilverlightApplication1.Web\ClientBin

    的檔案夾中生成xap檔案,将此檔案放入sharepoint的文檔庫中,然後在網頁中插入webpart,其指定的路徑即xap存儲對應的路徑。也可以放在伺服器可以通路到的路徑,但此時網頁緩存的問題難以解決

相關操作

說明:因為silverlight和sharepoint關聯時,是進行異步通信的,對資料的增上改查等操作都需要異步通信程式設計

* 初始化

private Condition stopCondition = new Condition();
    private PageProperty pagePro = PageProperty.IsAdd;//存儲網頁是建立還是編輯
    private ProTest.溫升實驗DataContext dc = null; 
    //進入該網頁時,會有相關資訊,
    //包括操作的資料項(如果有的話),以及跳轉的原網頁等資訊,将其存儲在字典裡
    private IDictionary<string, string> webInfo = HtmlPage.Document.QueryString;    
           

* 增加資料

private void AddData(Condition cSc)
    {
        bool addFail = false;

        //異步
        try
        {
            dc.StopCondition02.BeginExecute((result) =>
            {//lambda表達式
                try
                {
                    var items = dc.StopCondition02.EndExecute(result);
                    //下面這句話需要嘗試一下,因為之前這個查詢的任務不能運作
                    //if (items.Where(c => c.名字 == stopCondition.name) != null)
                    foreach (var item in items)
                    {
                        if (item.名字 == stopCondition.name)
                        {
                            addFail = true;
                            break;
                        }
                    }
                    if(addFail)
                    {
                        CTbForDebug.Text += "建立頁中已有該名稱,無法添加停止條件\n";
                    }
                    else
                    {
                        ProTest.StopCondition02Item pt = new ProTest.StopCondition02Item();
                        pt.名字 = cSc.name;
                        pt.資料 = cSc.Serialize();
                        pt.标準 = cSc.referCriterion;
                        pt.描述 = cSc.description;
                        pt.參數 = cSc.parameters;
                        pt.種類 = cSc.kind.ToString();
                        dc.AddToStopCondition02(pt);
                        dc.BeginSaveChanges((ar) =>
                        {
                            if (ar.IsCompleted)
                            {
                                CTbForDebug.Text += "添加成功\n";
                                CloseThisPage();
                            }
                            else
                            {
                                CTbForDebug.Text += "添加失敗\n";
                            }
                        }, null);
                    }
                }
                catch (Exception ex)
                {
                    CTbForDebug.Text += ex.Message;
                }
            }, null);
        }
        catch(Exception ee)
        {
            MessageBox.Show(ee.ToString());
        }
    }
           

* 編輯資料

編輯資料的語句和添加資料類似,隻是有以下幾個地方需要注意:

* 需要建立一個資料項的對象,當var對象找到時(資料庫中對應的資料項),将var類型隐式轉換為資料項對象,之後直接修改這個資料項的對象即可

* 修改結束後,需要利用以下方式進行更新

//dc.AttachTo("StopCondition02", (ProTest.StopCondition02Item)forChg);//這句話不加竟然也可以運作成功。。
        dc.UpdateObject(forChg);
第一句是将資料和資料項進行關聯,然而自己操作的時候發現根本不需要這一句。。boss之前測試說需要,我就先在這裡注釋掉,不行再加上。。
* 儲存資料庫
           

* 儲存資料

dc.BeginSaveChanges((ar) =>
    {
        if (ar.IsCompleted)
        {
            CTbForDebug.Text += "修改成功\n";
            CloseThisPage();
        }
        else
        {
            CTbForDebug.Text += "修改失敗\n";
        }
    }, null);
           

* 注:關于lambda表達式的使用問題

* 當初它的引入是為了友善程式設計,即省略某些函數的作用

* 現在發現,siverlight操作sharepoint的資料時,我因為不熟,不敢随意改,導緻現在的函數都是有多層嵌套的問題,顯得特變亂。

* 當嵌套層次比較多時,不建議用lambda表達式,直接用普通的異步程式設計即可。。然而我并沒有學過。。

C#生成二維碼

dll檔案

  • ThoughtWorks.QRCode.dll
  • 添加引用之後,需要在程式開始處添加

    using ThoughtWorks.QRCode.Codec;

生成二維碼函數

  • 代碼如下
    private void GenerateQR()
    {
    //Image image;
    //image = qrCodeEncoder.Encode(data, Encoding.UTF8);
    //MemoryStream ms = new MemoryStream();
    //image.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
    //byte[] bt = ms.ToArray();
    }
    
    /// 生成二維碼
    /// </summary>
    /// <param name="strData">要生成的文字或者數字,支援中文。如: "4408810820 深圳-廣州" 或者:4444444444</param>
    /// <param name="qrEncoding">三種尺寸:BYTE ,ALPHA_NUMERIC,NUMERIC</param>
    /// <param name="level">大小:L M Q H</param>
    /// <param name="version">版本:如 8</param>
    /// <param name="scale">比例:如 4</param>
    /// <returns></returns>
    public void CreateCode_Choose(string strData, string qrEncoding, string level, int version, int scale)
    {
        QRCodeEncoder qrCodeEncoder = new QRCodeEncoder();
        string encoding = qrEncoding;
        switch (encoding)
        {
            case "Byte":
                qrCodeEncoder.QRCodeEncodeMode = QRCodeEncoder.ENCODE_MODE.BYTE;
                break;
            case "AlphaNumeric":
                qrCodeEncoder.QRCodeEncodeMode = QRCodeEncoder.ENCODE_MODE.ALPHA_NUMERIC;
                break;
            case "Numeric":
                qrCodeEncoder.QRCodeEncodeMode = QRCodeEncoder.ENCODE_MODE.NUMERIC;
                break;
            default:
                qrCodeEncoder.QRCodeEncodeMode = QRCodeEncoder.ENCODE_MODE.BYTE;
                break;
        }
        qrCodeEncoder.QRCodeScale = scale;
        qrCodeEncoder.QRCodeVersion = version;
        switch (level)
        {
            case "L":
                qrCodeEncoder.QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.L;
                break;
            case "M":
                qrCodeEncoder.QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.M;
                break;
            case "Q":
                qrCodeEncoder.QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.Q;
                break;
            default:
                qrCodeEncoder.QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.H;
                break;
        }
        //文字生成圖檔
        Image image = qrCodeEncoder.Encode(strData);
        string filename = DateTime.Now.ToString("yyyymmddhhmmssfff").ToString() + ".jpg";
        string filepath = @"./jpg/";
        //如果檔案夾不存在,則建立
        if (!Directory.Exists(filepath))
            Directory.CreateDirectory(filepath);
        FileStream fs = new FileStream(filepath+filename, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write);
        image.Save(fs, System.Drawing.Imaging.ImageFormat.Jpeg);
        fs.Close();
        image.Dispose();
    }
               
  • 說明
    • 使用如下代碼即可生成二維碼
    • 代碼
      private string data = "233333";
      CreateCode_Choose(data , "BYTE" , "L" , 8 , 4 );//這裡的參數均是比較常用的參數
                 
    • 注:這種方法适合生成數字或者中英文字元的文本

将圖檔插入二維碼中

  • 代碼
    public Image GCode(String data)
    {
        QRCodeEncoder qrCodeEncoder = new QRCodeEncoder();
        qrCodeEncoder.QRCodeEncodeMode = QRCodeEncoder.ENCODE_MODE.BYTE;
        qrCodeEncoder.QRCodeScale = 5;
        qrCodeEncoder.QRCodeVersion = 7;
    
        qrCodeEncoder.QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.L;
        var pbImg = qrCodeEncoder.Encode(data, System.Text.Encoding.UTF8);
        var width = pbImg.Width / 10;
        var dwidth = width * 2;
        Bitmap bmp = new Bitmap(pbImg.Width + dwidth, pbImg.Height + dwidth);
        Graphics g = Graphics.FromImage(bmp);
        var c = System.Drawing.Color.White;
        g.FillRectangle(new SolidBrush(c), 0, 0, pbImg.Width + dwidth, pbImg.Height + dwidth);
        g.DrawImage(pbImg, width, width);
        g.Dispose();
        return bmp;
    }  
    
    /// <summary>  
    /// 調用此函數後使此兩種圖檔合并,類似相冊,有個  
    /// 背景圖,中間貼自己的目标圖檔  
    /// </summary>  
    /// <param name="sourceImg">粘貼的源圖檔</param>  
    /// <param name="destImg">粘貼的目标圖檔</param>  
    public static System.Drawing.Image CombinImage(System.Drawing.Image imgBack, string destImg)  
    {  
        Image img = System.Drawing.Image.FromFile(destImg);        //照片圖檔    
        if (img.Height != 50 || img.Width != 50) 
        {  
            img = KiResizeImage(img, 50, 50, 0);  
        }  
        Graphics g = Graphics.FromImage(imgBack);  
    
        g.DrawImage(imgBack, 0, 0, imgBack.Width, imgBack.Height);      //g.DrawImage(imgBack, 0, 0, 相框寬, 相框高);   
    
        //g.FillRectangle(System.Drawing.Brushes.White, imgBack.Width / 2 - img.Width / 2 - 1, imgBack.Width / 2 - img.Width / 2 - 1,1,1);//相片四周刷一層黑色邊框  
    
        //g.DrawImage(img, 照片與相框的左邊距, 照片與相框的上邊距, 照片寬, 照片高);  
    
        g.DrawImage(img, imgBack.Width / 2 - img.Width / 2, imgBack.Width / 2 - img.Width / 2 , img.Width, img.Height);  
        GC.Collect();  
        return imgBack;  
               

    }

    ///

    /// Resize圖檔

    ///

    /// 原始Bitmap

    /// 新的寬度

    /// 新的高度

    /// 保留着,暫時未用

    /// 處理以後的圖檔

    public static Image KiResizeImage(Image bmp, int newW, int newH, int Mode)

    {

    try

    {

    System.Drawing.Image b = new Bitmap(newW, newH);

    Graphics g = Graphics.FromImage(b);

    // 插值算法的品質  
          g.InterpolationMode = InterpolationMode.HighQualityBicubic;
    
          g.DrawImage(bmp, new Rectangle(0, 0, newW, newH), new Rectangle(0, 0, bmp.Width, bmp.Height), GraphicsUnit.Pixel);
          g.Dispose();
    
          return b;
      }
      catch
      {
          return null;
      }
               
    }
  • 運作以下:
    string data = "2333";
    Image im0 = GCode(data);
    Image im1 = CombinImage(im0 , "1.jpg");//重點所在
    string filename = DateTime.Now.ToString("yyyymmddhhmmssfff").ToString() + ".jpg";
    string filepath = @"./jpg/";
    //如果檔案夾不存在,則建立
    if (!Directory.Exists(filepath))
        Directory.CreateDirectory(filepath);
    FileStream fs = new FileStream(filepath + filename, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write);
    im1.Save(fs, System.Drawing.Imaging.ImageFormat.Jpeg); //儲存圖檔
    fs.Close();
    im0.Dispose();
    im1.Dispose();
               

委托

  • 代碼
    public delegate string DelegateExam(int num);//在類外進行申明或者裡面都行
    private void button13_Click(object sender, EventArgs e)
    {
        DelegateExam de = new DelegateExam(DecD); 
        Console.WriteLine(de(33));//輸出32
        Console.WriteLine((new DelegateExam(AddD))(44));//輸出45
    }
    private string AddD(int num)
    {
        return (num + 1).ToString();
    }
    private string DecD(int num)
    {
        return (num - 1).ToString();
    }
               

匿名

Func<string, string> AA = delegate(string name)
{
    name += "\nit's Nm";
    return name;
};
Console.WriteLine(AA("111"));
           

沒有委托的聲明,直接用Func實作(可以查閱資料)

lambda表達式

string mid = " it's middle ";
Func<string, string> lambda = para =>
    {
        para += "2333";
        para += mid;
        return para;
    };
Console.WriteLine(lambda("GRY"));
           

lambda是函數名,para是參數,ide可以自動識别它的類型,而且此處Func已經為他指定類型了。

=>

左邊列出了其參數,右邊是傳回值,如果很長的話,用大括号括起來,如果不長的話,用以下方法也可以。

Func<double,double,double> Mult = (x,y) => (x*y);
Console.WriteLine(Mult(5,2));
           

參數用小括号括起來,右邊直接寫結果即可,不用大括号和return。

IComparer接口的實作

網址

線程傳遞參數

網址

使用ParameterizedThreadStart(不推薦,因為可以接受任何類型的資料)

//線程類的建立
public class ThreadTest
{
    public static void RunTestWithPara(object data)
    {
        Console.WriteLine("para is {0}",data);
    }
}
//按鈕響應事件
private void button21_Click(object sender, EventArgs e)
{
    Thread[] th = new Thread[10];
    for (int i = 0; i < 10; i++)
    {
        th[i] = new Thread(new ParameterizedThreadStart(ThreadTest.RunTestWithPara));
    }
    for (int i = 0; i < 10; i++)
    {
        th[i].Start(i);
    }
}
           

注意:因為是線程啟動,是以不是按照嚴格的遞增的順序輸出0~9,每次運作時的輸出順序均不相同。

LINQ表達式與lambda表達式

  • 代碼
    List<string> list = new List<string>() {"list","ass","efrg","jhgkjs","jnbgt" };
    var strWithJ = from a in list
                   where a.StartsWith("j")
                   orderby a ascending
                   select a;
    foreach (var v in strWithJ)
        Console.WriteLine(v);
    Console.WriteLine("---------");
    var strA = list.Where((a, index) => a.StartsWith("j") && index % 2 == 0);
    foreach (var v in strA)
        Console.WriteLine(v);
               
    注:LINQ表達式是在每次運作foreach進行周遊時才執行搜尋過程,是以執行foreach時,操作的是最新的對象。
    var dd = from a in list
             group a by a[0] into g
             where g.Count() >= 1
             select new
             {
                 c11 = g.Key,
                 cnt = g.Count()
             };
    foreach (var ddd in dd)
    {
        Console.WriteLine("{0}---{1}",ddd.c11,ddd.cnt);
    }
    list.Add("jasld");
    foreach (var ddd in dd)
    {
        Console.WriteLine("{0}---{1}", ddd.c11, ddd.cnt);
    }
               
    group關鍵詞的操作
  • lookup和dictionary的操作
    • lookup隻能在一開始就初始化完成,在之後不能再改變,可以是1個Key對應多個Value,可以友善得将資料分組
    • Dictionary隻能是1個Key對應1個Value,如果沖突的話,會出現異常。

LINQ查詢相關

可以實作多級嵌套查詢

快捷鍵設定

目前界面時快捷鍵

  • 直接設定keyup的函數響應即可,但是要使其有效,需要使界面的

    KeyPreview

    設定為

    true

全局快捷鍵

  • 需要寫單獨的hotkey函數,這個需要參考網上的其他資料

工作線程

背景

  • 在進行一些比較耗時的操作時,希望界面沒有卡死,可以通過多線程操作,C#提供了一種比較友善的快捷方式

基本工作過程

  • 在界面中添加一個

    BackgroundWorker

    ,需要異步調用它的時候,直接調用

    bgWorker.RunWorkerAsync(1000);

    1000

    是傳入的參數,這個會異步調用

    bgWorker_DoWork

    ,傳入的參數可以通過

    e.Argument

    進行動态轉換。
  • 可以設定完成時的消息函數,即異步線程在調用結束之後會調用該函數,可以用于更新界面等操作。
  • 可以設定是否支援取消該工作線程,如果可以取消,則可以調用

    bgWork.CancelAsync();

    來取消目前的異步線程。
  • 每次異步線程隻能處理一個任務,是以如果需要處理多個相同類型的任務時,需要等待工作線程不是

    busy

    的狀态時,才能繼續處理下一個任務。

線程池

簡介

  • 程式可能會運用多個線程來進行操作,加快程式的運作速度,但是一般的多線程操作需要進行等待和喚醒等複雜的實作,十分麻煩,是以

    .NET架構

    為了簡化線程的處理,對每個程序都提供了一個線程池,友善對多個線程進行統一管理,程式可以根據需要來有效地管理線程。
  • 線程池是一種多線程處理方式,處理過程中,将任務添加到隊列,然後在建立線程後自動啟動這些任務。線程池的線程都是背景線程,可以通過設定線程池個數的最大值。超過最大值的其他線程需要排隊,等到其他線程完成後才能夠啟動。
  • 線程池中的每個線程都是預設的優先級,使用預設的堆棧大小。
  • 線程池比較适合需要執行一些需要多個線程的任務,比如檔案的批量處理等,進而提高吞吐量。

不适合使用線程池的環境

  • 某一個任務具有特定的優先級。
  • 如果具有可能會長時間運作(并是以會阻塞到其他任務)的任務
  • 如果需要将線程放到單線程單元中(線程池中的線程均處于多線程單元中)
  • 如果需要用永久辨別來辨別和控制線程,比如想使用專用線程來終止該線程,将其挂起或者按照名稱發現它。

C#中的使用

  • 有一個專門的ThreadPool類,用于實作線程池
  • 實作方法為
    ThreadPool.QueueUserWorkItem(new WaitCallback( Func ), obj);
    ThreadPool.QueueUserWorkItem(new WaitCallback( Func ));
               

如果有參數需要傳遞的話可以用第一種,沒有參數傳遞的話可以用第二種。

正規表達式

比對

8位日期_3位編号

的字元串

if (Regex.IsMatch(str, @"^(\d{8}_\d{3})$"))
{
    Console.WriteLine("right...");
}
else
{
    Console.WriteLine("wrong...");
}
           

宏定義

  • 參考連結:http://www.runoob.com/csharp/csharp-preprocessor-directives.html
  • 注意的地方
  • 在檔案的最開始定義(using命名空間之前)

手動配置程式集名稱

  • 需求:有時候需要根據不同的設定生成不同的exe輸出檔案的檔案名,可以通過修改

    AssemblyInfo.cs

    和項目的

    csproj

    檔案來實作
  • 參考連結:https://ask.helplib.com/c-Sharp/post_984916
  • 注意:上面是手動修改,不是很友善,是以在實際項目中不推薦這樣做

csc指令配置程式集資訊

  • 參考連結:(http://blog.csdn.net/zmqhbd/article/details/1916485)[http://blog.csdn.net/zmqhbd/article/details/1916485]

windows特殊目錄使用

  • 參考連結:http://blog.csdn.net/zym2002cn/article/details/6181491
  • 在編寫應用程式和服務的時候,使用者可能不一樣,是以特殊目錄的所在位置也是不同的,應用程式中,使用者主要是普通使用者,而服務一般是以System這個特殊使用者執行的,是以在使用特殊目錄的時候需要注意