顯示具有 C# 標籤的文章。 顯示所有文章
顯示具有 C# 標籤的文章。 顯示所有文章

2017年8月2日 星期三

「C#」USB經驗分享

在C#中,我們如果要確定我們要通訊的USB裝置是否已連接,

通常會用PID/VID去判斷裝置是否存在。

最近遇到一個問題,有一個DFU裝置,驅動安裝失敗,但依然可以偵測到PID/VID。

但沒有驅動程式,是無法正確運作的。




















最終我是用USB Descriptor 去判斷是否有安裝驅動。

在未安裝驅動前,它的USB Descriptor為"DFU in FS Module",

但在安裝驅動後,它的USB Descriptor為"STM Device  in DFU Mode"


一開始誤以為沒有驅動,它不會被讀到。。。。。觀念錯誤。

上了一課,怪不得出現莫明其妙偵測的到,卻無法動彈的情況。

2017年6月20日 星期二

[C#]Array.Join

最近遇到一個需求,把1234 ---> 1,2,3,4

所以用到String.Join這個方法

public static string Join(
 string separator,
 params string[] value
)

第一個參數separator是表示你要用什麼分隔符號,例如,。

第二個參數則是要合併的String Array 


使用範例如下,輸出為1,2,3,4



String source="1234";
char[] charArray=source.ToCharArray();
String dist=String.Join(",",charArray);
Console.WriteLine(dist);

參考網頁:

https://msdn.microsoft.com/zh-tw/library/57a79xd0(v=vs.110).aspx

2016年12月30日 星期五

[C#] 讀取center 306 thermometer

今天遇到一個很神奇的溫度計,Center 306 thermometer ,需要用PC透過RS232 ,

將溫度值讀出來。


首先它的連接參數如下:

Baud Rate : 9600 , N , 8 , 1

需要設定啟用以下設定,否則會一直發送卻沒有人回你。

DTR – Data Terminal Ready

RTS – Request To Send


接下來說明Command



RS232 command
Function
Remarks
K(ASC 4BH)
Ask for model No.
Return 4 bytes
A(ASC 41H)
Inquire all encoded data
Return encoded 10 byte
H(ASC 48H)
Hold button

M(ASC 4DH)
MAX/MIN button

N(ASC 4EH)
Exit MAX/MIN mode

T(ASC 52H)
TIME button

C(ASC 43H)
C/F button

U(ASC 55H)
Dump all memory of thermometer
return 32768 bytes
P(ASC 50H)
Load recorded data


主要會用到2個,一個是K,一個是A。

K是會回傳型號,例如'3' '0' '6'  ASCII(13) ,'3'  '0'  '1'  ASCII(13) 。

而A則是溫度資訊,其他的功能本次沒有實作。

301和306在溫度的回傳的資料,有差一個byte,在實作時要注意。

我有一組306的回傳值,共九個BYTE。

02 80 00 B2 29 BB 00 B2 28 03

只會用到其中5個byte

第2個byte的第1個bit和第4個bit (由0開始計算)表示T1和T2是否為負值(1為負值)。

例如目前為00, 則T1和T2都是正值。

第3~4個BYTE代表T1的溫度值,B2 29  --> 022.9 ℃

第7~8個BYTE代表T2的溫度值,B2 28  --->022.8 ℃

一開始我是把B給濾掉,但後來發現降到9.8℃ 時,會出現BB.98 ,才推測B是0  。


以下是我的程式碼



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;
using System.Collections;
namespace TEST
{
    class Center_306
    {

        private SerialPort port;
        private Test.Form1.MyDelegate md;
        public Center_306(String comport, TH300Monitor.Form1.MyDelegate md)
        {
            this.md = md;
            port = new SerialPort(comport, 9600, Parity.None, 8, StopBits.One);
           // Enable DTR  
            bool s = port.DtrEnable = true;
            port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
        }

        public void QueryTemp()
        {
            port.Write(new char[] { 'A' }, 0, 1);
        }


        private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {

            int bytes = port.BytesToRead;
            byte[] comBuffer = new byte[bytes];
            port.Read(comBuffer, 0, bytes);
            if (bytes == 9)
            {

                byte[] t1 = new byte[2];
                byte[] t2 = new byte[2];

                bool t1_sign = (comBuffer[2] & (1 << 1)) != 0;
                bool t2_sign = (comBuffer[2] & (1 << 4)) != 0;



                Array.Copy(comBuffer, 3, t1, 0, 2);
                Array.Copy(comBuffer, 7, t2, 0, 2);


                string hex1=BitConverter.ToString(t1);
                string hex2 = BitConverter.ToString(t2);

                hex1 = hex1.Replace("-", "").Replace("B", "0");
                hex2 = hex2.Replace("-", "").Replace("B", "0");
                
                double temp1 = Double.Parse(hex1) / 10.0;
                double temp2 = Double.Parse(hex2) / 10.0;

                if (t1_sign == true)
                {
                    temp1 = temp1 * -1;
                }

                if (t2_sign == true)
                {
                    temp2 = temp2 * -1; 
                }

                Console.WriteLine(temp1 + " " + temp2);

                md.Invoke(temp1, temp2);
            }
        }


      

        public void Open()
        {
            port.Open();
        }

        public void Close()
        {
            port.Close();
        }
    }
}

呼叫方式如下:


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using TH300;
using System.IO.Ports;

namespace TH300Monitor
{
    public partial class Form1 : Form
    {
   
        //add for Center 306
        public delegate void MyDelegate(double temp1, double temp2);
        Center_306 c306;
        MyDelegate oMyDel;

       bool isConnect=false;

        public Form1()
        {
            InitializeComponent();
        }

        private void btnConn_Click(object sender, EventArgs e)
        {
            

            TimerRead.Enabled = true;
          
            //add center 306 
            oMyDel = new MyDelegate(Show);
            c306 = new Center_306(C306_com.Text, oMyDel);

            c306.Open();

    
        }


        //for center 306 display
        MyDelegate uu;
        public void Show(double temp1, double temp2)
        {

            if (this.InvokeRequired)
            {
                uu = new MyDelegate(Show);
                this.Invoke(uu, temp1, temp2);
            }
            else
            {
                c306_temp1.Text = temp1.ToString();
                c306_temp2.Text = temp2.ToString();
            }
        }

        private void btnDisconn_Click(object sender, EventArgs e)
        {
            TimerRead.Stop();
            System.Threading.Thread.Sleep(1000);

            //ad for center 306
            
            c306.Close();
        }

      

        private void btnStop_Click(object sender, EventArgs e)
        {
            TimerRead.Stop();
            
        }

        /// <summary>
        /// Read data per sec  
        /// </summary>
        private void TimerRead_Tick(object sender, EventArgs e)
        {
            

            //add for c306
            c306.QueryTemp();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
          

            // Set Timer
            TimerRead.Interval = 1000;
        }

    }
}

當有回傳值時,會自動顯示在c306_temp1及c306_temp2 二個Lable上




參考資料

C306
https://www.instrumart.com/assets/MARTEL306_manual.pdf

C301差異截圖



2016年12月25日 星期日

[C#] 簡單繼承例子

一個簡單的繼承例子

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            new MyClass();

            Console.ReadKey();
        }
    }

    class BaseClass
    {
        public BaseClass()
        {
            Console.Write("boywhy");
        }
    }

    class MyClass:BaseClass
    {
        public MyClass()
        {
            Console.Write("blogger");
        }
    }
}


輸出為:


boywhyblogger


因為父類別的建構子中己經輸出了boywhy,而繼承的子類別中的建構子也輸出blogger,

所以輸出為boywhyblogger


2016年12月24日 星期六

「C#」掛載遠端資料夾為磁碟機

弄了一個Class,可以掛載遠端磁碟。

記得要引入 Windows Script Host Object Model參考




























using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using IWshRuntimeLibrary;   //Add "Windows Script Host Object Model" COM reference
using System.IO;
using System.Collections;

namespace Mount_Data
{
    class NetworkDriver
    {
        private WshNetwork _networkShell = new WshNetwork();

        private void MapDrive(string driveLetter, string UNC, bool isPersistent, string userName, string password)
        {
            if (driveLetter != "")
            {
                DisconnectDrive(driveLetter, true, true);
            }
            else
            {
                DisconnectDrive(UNC, true, true);
            }
            object persistent = isPersistent;
            object user = userName;
            object pwd = password;
            _networkShell.MapNetworkDrive(driveLetter, UNC, ref persistent, ref user, ref pwd);
        }

        private void DisconnectDrive(string UNC_or_DriveName, bool willForce, bool isPersistent)
        {
            try
            {
                object force = willForce;
                object updateProfile = isPersistent;
                _networkShell.RemoveNetworkDrive(UNC_or_DriveName, ref force, ref updateProfile);
            }
            catch
            {
                //
            }
        }


        /// <summary>
        /// Mount Remote disk
        /// </summary>
        /// <param name="sour_path">remote source path , ex: @"file://123.456.789.123/qq" </param>
        /// <param name="DriveLable">remote disk lable , ex: X, Y ,Z </param>
        /// <param name="user_id"></param>
        /// <param name="password"></param>
        public void MAP_DRIVER(String sour_path, string DriveLable,string user_id,string password)
        {
            
            MapDrive(DriveLable+":", sour_path, false, user_id, password);
        }

        /// <summary>
        ///  Umount
        /// </summary>
        public void DIS_MAP_DRIVER(string DriveLable)
        {
            DisconnectDrive(DriveLable+":", true, true);          
        }

        public char getFreeLabel()
        {
            char letter = ' ';
            ArrayList driveLetters = new ArrayList(26); // Allocate space for alphabet
            for (int i = 65; i < 91; i++) // increment from ASCII values for A-Z
            {
                driveLetters.Add(Convert.ToChar(i)); // Add uppercase letters to possible drive letters
            }

            foreach (string drive in Directory.GetLogicalDrives())
            {
                driveLetters.Remove(drive[0]); // removed used drive letters from possible drive letters
            }

            foreach (char drive in driveLetters)
            {
                //comboDrives.Items.Add(drive); // add unused drive letters to the combo box
                letter = drive;
                break;
            }
            return letter;
        }


    }
}

記得先去一個空的磁碟機代號,可以參考這篇 ,以下是使用範例。


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        //«Å§i¤@­ÓNetworkDiriverª«¥ó¡A¥Î¨Ó±¾¸ü»·ºÝºÏºÐ
        NetworkDriver nd = new NetworkDriver();
        public Form1()
        {            InitializeComponent();
            
        }

        private void button1_Click(object sender, EventArgs e)
        {
           
            //UNC format \\IP\folder ,  don't use \\IP\folder\\ 
            nd.MAP_DRIVER(@"\\192.168.1.109\­個人資料夾","z","username","password");
        }

        private void button2_Click(object sender, EventArgs e)
        {
            nd.DIS_MAP_DRIVER("z");
        }
    }
}


注意一下,遠端磁碟是採用一種叫UNC的路徑格式, \\IP\\Folder  ,

不要多打了一個\ ,變成\\IP\\Folder\\ ,會連到Timerout






按下Mount後,會Mount指定的遠端磁碟,按下Umount會中斷連接


按下Mount後會出出一個遠端磁碟



按下Umount之後會消失














[C# ] TabPage Hide and Show

讓TabPage顯示或隱形有一個蠻簡單的方法,效果如下


將TabPage顯示





















將TabPage隱形






















程式碼如下


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        TabPage mMoneyPage;
        public Form1()
        {
            InitializeComponent();

            //get Tabpage ref 
            for (int i = 0; i < tabControl1.TabPages.Count; i++)
            {
                if (tabControl1.TabPages[i].Name.Equals("money"))
                {
                    mMoneyPage = tabControl1.TabPages[i];
                }
            }
        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            if (mMoneyPage != null)
            {
                if (((CheckBox)sender).Checked)
                {
                    mMoneyPage.Parent = tabControl1;
                }
                else
                {
                    mMoneyPage.Parent = null;
                }
            }
            
        }
    }
}

2016年11月24日 星期四

[C#] 改變陣列的長度

C# 提供一個方式,讓我們可以很輕的改變Array長度,並且保留原本的資料

public static void Resize<T> (
 ref T[] array,
 int newSize
)

使用方法如下

Array.Resize(ref 你的陣列 , 新的長度)

以下是一個範例,把陣列加長,並印出資料


using System;
using System.Collections.Generic;


namespace Rextester
{
    public class Program
    {
        public static void Main(string[] args)
        {
            
            int[] number=new int[20];
            
            for (int i=0;i<number.Length;i++)
            {
                number[i]=i+1;
            }
            
            Array.Resize(ref number,30);
            
            int idx=0;
            foreach(int n in number)
                Console.WriteLine("number["+(idx++)+"]="+n);
        }
    }
}

執行結果:

number[0]=1
number[1]=2
number[2]=3
number[3]=4
number[4]=5
number[5]=6
number[6]=7
number[7]=8
number[8]=9
number[9]=10
number[10]=11
number[11]=12
number[12]=13
number[13]=14
number[14]=15
number[15]=16
number[16]=17
number[17]=18
number[18]=19
number[19]=20
number[20]=0
number[21]=0
number[22]=0
number[23]=0
number[24]=0
number[25]=0
number[26]=0
number[27]=0
number[28]=0
number[29]=0

你可以發現,資料都還在,陣列也如我所願變長了,接下來我們試試變短看看

Array.Resize(ref number,10);

輸出結果如下

number[0]=1
number[1]=2
number[2]=3
number[3]=4
number[4]=5
number[5]=6
number[6]=7
number[7]=8
number[8]=9
number[9]=10

資料依然完好無損。

[c#] 取得字型目錄

取得字型所在地的目錄
string fontsfolder = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Fonts);

「C#」將DataTable的值輸出成PDF

首先你需要到這裡下載一個範例程式,它裡面會有我們需要的itextsharp.dll

http://www.aspsnippets.com/Articles/Export-Windows-Forms-DataGridView-to-PDF-using-iTextSharp-C-and-VBNet.aspx


他內附的範例程式會有一個蠻冏的問題,中文字會不見,不過外國人沒這煩惱。

我爬了一些文之後,修正了這個問題,需要指定字型。


首先,你必須在專案中建用itextsharp.dll。

接下來將以下這段範例程式將會把datagridview1的內容,包含標題列,都丟到PDF中


//設定中文字體           
string fontsfolder = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Fonts);
string chFontPath = fontsfolder+ "\\KAIU.ttf";//windows內建的SimHei字體(中易黑體)                            
BaseFont chBaseFont = BaseFont.CreateFont(chFontPath, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);

Phrase helloPhrase = new Phrase();
iTextSharp.text.Font twFont = new iTextSharp.text.Font(chBaseFont, 14);

//Creating iTextSharp Table from the DataTable data
PdfPTable pdfTable = new PdfPTable(dataGridView1.ColumnCount);
           
pdfTable.DefaultCell.Padding = 3;
//use 100% page width
pdfTable.WidthPercentage = 100; pdfTable.HorizontalAlignment = Element.ALIGN_LEFT; pdfTable.DefaultCell.BorderWidth = 1; //Adding Header row foreach (DataGridViewColumn column in dataGridView1.Columns) {
       //Asign Chinese Font to cell
      PdfPCell cell = new PdfPCell(new Phrase(column.HeaderText,twFont));
      cell.BackgroundColor = new iTextSharp.text.Color(240, 240, 240);
      pdfTable.AddCell(cell);
}

//Adding DataRow
foreach (DataGridViewRow row in dataGridView1.Rows)
{
  foreach (DataGridViewCell cell in row.Cells)
  {
      if (cell.Value!=null)
      {
                        
           PdfPCell datacell = new PdfPCell(new Phrase(cell.Value.ToString(), twFont));
           datacell.BackgroundColor = new iTextSharp.text.Color(255, 255, 255);
           pdfTable.AddCell(datacell);
                                               
      }
  }
}

//Exporting to PDF
string folderPath = Environment.CurrentDirectory+"\\";
if (!Directory.Exists(folderPath))
{
   Directory.CreateDirectory(folderPath);
}
using (FileStream stream = new FileStream(folderPath + "blogger.pdf", FileMode.Create))
{
   Document pdfDoc = new Document(PageSize.A2, 10f, 10f, 10f, 0f);
   PdfWriter.GetInstance(pdfDoc, stream);
   pdfDoc.Open();
   pdfDoc.Add(pdfTable);
   pdfDoc.Close();
   stream.Close();
 }

參考連結:

Export Windows Forms DataGridView to PDF using iTextSharp, C# and VB.Nethttp://www.aspsnippets.com/Articles/Export-Windows-Forms-DataGridView-to-PDF-using-iTextSharp-C-and-VBNet.aspx

中文輸出問題解法參考
https://dotblogs.com.tw/kevinya/2015/12/24/163050

[C#] TextBox Hint Text

C# TextBox沒有像Android的Hint,可以在使用者未輸入內容時,顯示提示字。

在網路上找到一段程式碼,感覺蠻好用的。


private const int EM_SETCUEBANNER = 0x1501;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern Int32 SendMessage(IntPtr hWnd, int msg, int wParam, [MarshalAs(UnmanagedType.LPWStr)]string lParam);

private void Form1_Load(object sender, EventArgs e)
{

    SendMessage(textBox1.Handle, EM_SETCUEBANNER, 0, "Input Number");
}

執行效果

























注意一下,第3個參數是0或1的差別

當是0的時候,只要TextBox取得焦點,把輸入內容刪除後,依然還是顯示空白,

必須當其他控制項取得焦點時,才會顯示提示字,如下所示。















當是1的時候,只要沒有輸入內容,就會出現提示字。


不過,在XP似乎沒有效果@@

2016年11月22日 星期二

[C#] 寫TXT換行失效解法

有時候我們在寫文字檔時,在字串最後加上\n\r,但卻沒有成功換行。

後來發現一個有效的解法,也不用去在意各個系統的換行字元。


Environment.NewLine


用這個就可以換行了。

[C#] .Net Framework 3.5 在For迴圈中跑執行緒

Net Framework 4 推出了Parallel.For ,讓迴圈中發揮多核心的威力,簡化許多。

但在.Net Framework 3.5 中並沒有這種好東西可以用,如果要實作在F or迴圈中擠出

多核心的效能,可以用以下方式實作。


首先介紹ManualResetEvent ,這是一個很好用的東西,可以用來卡住目前的流程。

ManualResetEvent.Reset時,流程會卡住在ManualResetEvent.WaitOne()的地方,直到

ManualResetEvent.set()為止,若一直忘記Reset,會卡到無怨無悔,畫面臉色發白。

以下是一個簡單的範例,當所有執行緒執行完畢後,才會印出目前時間。




using System;
using System.Threading;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication
{
    public class Program
    {
        public static void Main(string[] args)
        {
            new Program();
        }
        
        //Define Thread Control Var
        int DoneCount = 0;
        int DoneRequired =0;
        ManualResetEvent mre = new ManualResetEvent(false);
        
        public Program()
        {
         round();
        }
        
        private void round()
        {
               int N=10;
               ParameterizedThreadStart pts ;
               Thread mThread;
               
               DoneCount = 0;
               DoneRequired =N;
            
               mre.Reset();
              for (int i=0;i<N;i++)
              {
                pts = new ParameterizedThreadStart(ThreadFunction);
                mThread=new Thread(pts);
                mThread.Start(i);
              }
             //wait all thread finish 
             mre.WaitOne();
             Console.Write("Done "+DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss")+Environment.NewLine);
        }
        
         private void ThreadFunction(object data)
        {             
            int n=Convert.ToInt32(data);
            
            System.Threading.Thread.Sleep(n*100);
                 
            Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss")+" sleep:"+n*100);
            Interlocked.Increment(ref DoneCount);           
            if (DoneCount == DoneRequired)
            {
                mre.Set();
            }
        }
      
    }
}

執行結果:


2016-11-22 10:22:34 sleep:0
2016-11-22 10:22:34 sleep:100
2016-11-22 10:22:34 sleep:200
2016-11-22 10:22:34 sleep:300
2016-11-22 10:22:34 sleep:400
2016-11-22 10:22:35 sleep:500
2016-11-22 10:22:35 sleep:600
2016-11-22 10:22:35 sleep:700
2016-11-22 10:22:35 sleep:800
2016-11-22 10:22:35 sleep:900
Done 2016-11-22 10:22:35

如果我們沒有使用ManualResetEvent來控制流程,則會變成以下結果

把mre.set()以及mre.WaitOne()註解掉


Done 2016-11-22 10:25:15
2016-11-22 10:25:15 sleep:0
2016-11-22 10:25:15 sleep:100
2016-11-22 10:25:15 sleep:200
2016-11-22 10:25:15 sleep:300
2016-11-22 10:25:15 sleep:400
2016-11-22 10:25:15 sleep:500
2016-11-22 10:25:15 sleep:600
2016-11-22 10:25:15 sleep:700
2016-11-22 10:25:15 sleep:800
2016-11-22 10:25:16 sleep:900

就會變成我也不知道Thread何時跑完,但我己先印出結束時間了。