上色

Code Block

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

2018年7月9日 星期一

[.Net] 以string,Join串接array of array(jagged array)

大家都知道使用string.Join可以串接陣列或清單中字串,像是下面這樣的形式
string[] source = new string[]{"one", "two", "three"};
string result = string.Join(",", source);

但是當陣列中還有陣列(jagged array, e.g. array of array)的時候怎麼辦呢?
這時候LINQ的Select語法就派上用場了,一層一層的串上去就對了
string[][][] source = new string[][][]{
 new string[][]{
  new string[]{"1", "2", "3"},
  new string[]{"one", "two", "three"}
 },
 new string[][]{
  new string[]{"4", "5", "6"},
  new string[]{"five", "six", "seven"}
 }
};

string result = string.Join(",", source.Select(m => string.Join(",", m.Select(n => string.Join(",", n)))));

如此一來就可以成功串接每一層陣列中的字串了。

Reference:
https://stackoverflow.com/questions/35102320/c-sharp-copying-jagged-arrays-to-strings


2018年7月4日 星期三

[.Net] Office interop runtime無法執行

紀錄一下最近遇到的問題,使用C#於MS Office 2013的環境上開發了一個程式,於MS Office 2010的機器上運作正常,但拿到MS Office 2007的機器上運作就會報錯。

首先,PIAs(Primary Interop Assemblies)必須與想要支援的最低版本相容,亦即想要支援Office 2007的話就必須使用v12的PIAs。
所以必須在Project的reference中加入v12版本的office PIAs(可以使用NuGet直接找到v12版本的PIA,亦即Microsoft.Office.Interop(v12)加入);但是光這樣是不夠的,因為當你的機器上有安裝更新版Office(如Office 2013)的時候,編譯時候會自動redirect到新版的PIAs,也就是在本機的GAC(global assembly cache)中所安裝的版本。

要修正這個問題,必須停止所謂的assembly binding redirection,可依照下列步驟進行:

1. 打開C:\Windows\Assembly\GAC或C:\Windows\Assembly\GAC_MSIL資料夾(根據你的windows版本而定)。
2. 找到對應的PIA,如我要使用Word的PIA,就找到Policy.12.0.Microsoft.Office.Interop.Word這樣的資料夾。
3. 在資料夾中找到設定的xml檔案,將下面這段註解掉
<bindingredirect newversion="14.0.0.0" oldversion="12.0.0.0"></bindingredirect>
變成
<!--<bindingredirect newversion="14.0.0.0" oldversion="12.0.0.0"></bindingredirect>-->
如此一來就會不會在redirect到新版本的PIAs,可以達到在不同機器上的相容性。

Reference:
https://stackoverflow.com/questions/6984733/office-2007-pia

2016年6月3日 星期五

[.Net] 讀取CSV出現亂碼

當CSV檔中含有中文時,使用StremReader讀取通常都會出現亂碼,這是因為.Net預設使用Unicode編碼,但通常Excel還是使用Big5編碼,此時只要以下列方式指定系統編碼即可解決;
System.IO.FileStream fs = new System.IO.FileStream(fileName, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.ReadWrite);
System.IO.StreamReader sr = new System.IO.StreamReader(fs, System.Text.Encoding.Default);
使用System.Text.Encoding.Default指定系統預設編碼為StremReader的編碼格式。

[.Net] 字串轉為DateTime

通常需要將字串轉為DateTime的時候,一大問題就是來源格式常常不是固定的格式,而是有各種五花八門的格式,這時候就可以利用以下方式進行轉換:

首先定義可能出現的各種日期格式,可參照https://msdn.microsoft.com/en-us/library/8kb3ddd4(VS.71).aspx

string[] dateTimeList = { 
 "yyyy/M/d tt hh:mm:ss", 
 "yyyy/MM/dd tt hh:mm:ss", 
 "yyyy/MM/dd HH:mm:ss", 
 "yyyy/M/d HH:mm:ss", 
 "yyyy/M/d", 
 "yyyy/MM/dd",
 "M/d HH:mm:ss"
}; 

接著就可以開始處理字串,使用CultureInfo.InvariantCulture解析不同國家語言格式的字串(或是套用目前的國家地區設定解析,CultureInfo.CurrentCulture),使用DateTimeStyles.AllowWhiteSpaces避免字串中可能出現的無意義空白;此外為了避免依然轉換錯誤,可以將整段敘述加入到Try...Catch區塊中,再於Catch區塊中對轉換錯誤加以處理。

string DateTime date;
try
{
 date = DateTime.ParseExact(dateString, dateTimeList, CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces);
 transferFlag = true;
}
catch (Exception e)
{
 throw new Exception("日期格式錯誤: " + e.Message);
}

Ref: https://dotblogs.com.tw/chhuang/2008/03/18/1921

2015年7月31日 星期五

[C#] Load custom cursor from resources

Sometime you need a custom cursor for your application, the following step let you use your custom cursor in the resources.


  1. Add cursor files (*.cur) to resources
    • In [Properties] -> [Resources] tab, click [Add Resource] -> [Add Existing File...]
    • Choose your custom cursors and click OK.
  2. Load cursor with following code:
this.Cursor = new Cursor(new System.IO.MemoryStream(Properties.Resources.MyCursor));
, where Mycursor refers to your cursor name.

2015年7月25日 星期六

[C#] 取得picture box在zoom模式時的正確圖片座標

private Point unScale(Point scaledP)
{
 if (picturebox1.SizeMode != PictureBoxSizeMode.Zoom) //only zoom mode need to scale
  return scaledP;
 Point unscaled_p = new Point();
 // image and container dimensions
 int w_i = picturebox1.Image.Width;
 int h_i = picturebox1.Image.Height;
 int w_c = picturebox1.Width;
 int h_c = picturebox1.Height;
 float imageRatio = w_i / (float)h_i; // image W:H ratio
 float containerRatio = w_c / (float)h_c; // container W:H ratio

 if (imageRatio >= containerRatio)
 {
  // horizontal image
  float scaleFactor = w_c / (float)w_i;
  float scaledHeight = h_i * scaleFactor;
  // calculate gap between top of container and top of image
  float filler = Math.Abs(h_c - scaledHeight) / 2;
  unscaled_p.X = (int)(scaledP.X / scaleFactor);
  unscaled_p.Y = (int)((scaledP.Y - filler) / scaleFactor);
 }
 else
 {
  // vertical image
  float scaleFactor = h_c / (float)h_i;
  float scaledWidth = w_i * scaleFactor;
  float filler = Math.Abs(w_c - scaledWidth) / 2;
  unscaled_p.X = (int)((scaledP.X - filler) / scaleFactor);
  unscaled_p.Y = (int)(scaledP.Y / scaleFactor);
 }
 return unscaled_p;
}

2015年7月22日 星期三

[C#] Rotate bitmap with a special angle

public unsafe void Rotate(Bitmap bmp, float angle)
{
  int width=bmp.Width;
  int height=bmp.Height;
 /*
  * right, down = positive
  * p1------------p2
  * |            | 
  * p4------------p3
  * 
  * p1(0,0), p2(width-1,0), p3(width-1,height-1), p4(0,height-1)
  * 
  * In this coordinate system(left-handed coordinate system), clockwise rotation matrix (theta): (cos -sin 
  *                                                                                               sin  cos)
  * 
  */
 //Calculate new vertex
 Point p1 = RotatePoint(new Point(0, 0), angle);
 Point p2 = RotatePoint(new Point(width - 1, 0), angle);
 Point p3 = RotatePoint(new Point(width - 1, height - 1), angle);
 Point p4 = RotatePoint(new Point(0, height - 1), angle);
 //Calculate new size
 int dstWidth = Math.Max(Math.Abs(p3.X - p1.X) + 1, Math.Abs(p4.X - p2.X) + 1);
 int dstHeight = Math.Max(Math.Abs(p3.Y - p1.X) + 1, Math.Abs(p4.Y - p2.Y) + 1);
 /*
  * Calculate offset between old and new coordinate system
  * left-top point in new coordiante system -> (0,0)
  * 
  */
 int offsetX = -new int[4] { p1.X, p2.X, p3.X, p4.X }.Min();
 int offsetY = -new int[4] { p1.Y, p2.Y, p3.Y, p4.Y }.Min();
 //create bmp
 Bitmap dstBitmap = new Bitmap(dstWidth, dstHeight, PixelFormat.Format32bppArgb);
 Rectangle srcRect = new Rectangle(0, 0, width, height);
 Rectangle dstRect = new Rectangle(0, 0, dstWidth, dstHeight);
 BitmapData srcBmpData = bmp.LockBits(srcRect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
 BitmapData dstBmpData = dstBitmap.LockBits(dstRect, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
 //define sin and cos
 double sin = Math.Sin(angle * Math.PI / 180);
 double cos = Math.Cos(angle * Math.PI / 180);
 int srcStride = srcBmpData.Stride;
 int dstStride = dstBmpData.Stride;
 //define pointer
 byte* srcP = (byte*)srcBmpData.Scan0.ToPointer();
 byte* dstP = (byte*)dstBmpData.Scan0.ToPointer();
 Parallel.For(0,dstHeight,i=>
 {
  Parallel.For(0, dstWidth, j =>
  {
   int k = 4 * j + i * dstStride;
   //Calculate corresponding point in old coordinate system
   Point oldPoint = RotatePoint(new Point(j - offsetX, i - offsetY), -angle);
   if (oldPoint.X >= 0 && oldPoint.X < width && oldPoint.Y >= 0 && oldPoint.Y < height)
   {
    dstP[k] = srcP[4 * oldPoint.X + srcStride * oldPoint.Y];
    dstP[k + 1] = srcP[4 * oldPoint.X + srcStride * oldPoint.Y + 1];
    dstP[k + 2] = srcP[4 * oldPoint.X + srcStride * oldPoint.Y + 2];
    dstP[k + 3] = srcP[4 * oldPoint.X + srcStride * oldPoint.Y + 3];
   }
   else
   {
    dstP[k] = dstP[k + 1] = dstP[k + 2] = 0xff;
    dstP[k + 3] = 0x0;
   }
  });
 });
 bmp.UnlockBits(srcBmpData);
 dstBitmap.UnlockBits(dstBmpData);
 bmp = (Bitmap)dstBitmap.Clone();
 dstBitmap.Dispose();
 width = bmp.Width;
 height = bmp.Height;
}