2019年6月10日 星期一

[C#] 實現 DataGridView 標頭自動排序

1.建立SortableBindingList類別,繼承BindingList,實作排序功能。

    public class SortableBindingList<T> : BindingList<T>
    {
        private readonly Dictionary<Type, PropertyComparer<T>> comparers;
        private bool isSorted;
        private ListSortDirection listSortDirection;
        private PropertyDescriptor propertyDescriptor;

        public SortableBindingList()
            : base(new List<T>())
        {
            this.comparers = new Dictionary<Type, PropertyComparer<T>>();
        }

        public SortableBindingList(IEnumerable<T> enumeration)
            : base(new List<T>(enumeration))
        {
            this.comparers = new Dictionary<Type, PropertyComparer<T>>();
        }

        protected override bool SupportsSortingCore
        {
            get { return true; }
        }

        protected override bool IsSortedCore
        {
            get { return this.isSorted; }
        }

        protected override PropertyDescriptor SortPropertyCore
        {
            get { return this.propertyDescriptor; }
        }

        protected override ListSortDirection SortDirectionCore
        {
            get { return this.listSortDirection; }
        }

        protected override bool SupportsSearchingCore
        {
            get { return true; }
        }

        protected override void ApplySortCore(PropertyDescriptor property, ListSortDirection direction)
        {
            List<T> itemsList = (List<T>)this.Items;

            Type propertyType = property.PropertyType;
            PropertyComparer<T> comparer;
            if (!this.comparers.TryGetValue(propertyType, out comparer))
            {
                comparer = new PropertyComparer<T>(property, direction);
                this.comparers.Add(propertyType, comparer);
            }

            comparer.SetPropertyAndDirection(property, direction);
            itemsList.Sort(comparer);

            this.propertyDescriptor = property;
            this.listSortDirection = direction;
            this.isSorted = true;

            this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
        }

        protected override void RemoveSortCore()
        {
            this.isSorted = false;
            this.propertyDescriptor = base.SortPropertyCore;
            this.listSortDirection = base.SortDirectionCore;

            this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
        }

        protected override int FindCore(PropertyDescriptor property, object key)
        {
            int count = this.Count;
            for (int i = 0; i < count; ++i)
            {
                T element = this[i];
                if (property.GetValue(element).Equals(key))
                {
                    return i;
                }
            }

            return -1;
        }
    }

    public class PropertyComparer<T> : IComparer<T>
    {
        private readonly IComparer comparer;
        private PropertyDescriptor propertyDescriptor;
        private int reverse;

        public PropertyComparer(PropertyDescriptor property, ListSortDirection direction)
        {
            this.propertyDescriptor = property;
            Type comparerForPropertyType = typeof(Comparer<>).MakeGenericType(property.PropertyType);
            this.comparer = (IComparer)comparerForPropertyType.InvokeMember("Default", BindingFlags.Static | BindingFlags.GetProperty | BindingFlags.Public, null, null, null);
            this.SetListSortDirection(direction);
        }

        #region IComparer<T> Members

        public int Compare(T x, T y)
        {
            return this.reverse * this.comparer.Compare(this.propertyDescriptor.GetValue(x), this.propertyDescriptor.GetValue(y));
        }

        #endregion

        private void SetPropertyDescriptor(PropertyDescriptor descriptor)
        {
            this.propertyDescriptor = descriptor;
        }

        private void SetListSortDirection(ListSortDirection direction)
        {
            this.reverse = direction == ListSortDirection.Ascending ? 1 : -1;
        }

        public void SetPropertyAndDirection(PropertyDescriptor descriptor, ListSortDirection direction)
        {
            this.SetPropertyDescriptor(descriptor);
            this.SetListSortDirection(direction);
        }
    }

2.將SortableBindingList物件繫結至DataGridView。

dataGridView.DataSource = new SortableBindingList<T>(List<T>之資料);

2019年6月6日 星期四

[C#] DataGridView 隔列換色

1.以foreach迴圈走訪DataGridViewRow物件,再以IndexOf取出索引。

   public static void OddEvenColor(DataGridView dgv)
   {
      if (dgv.Rows.Count == 0) return;

      foreach (DataGridViewRow row in dgv.Rows)
      {
         int index = dgv.Rows.IndexOf(row);
         if (index % 2 == 0)
         {
            row.DefaultCellStyle.BackColor = Color.LightGray;
         }
         else
         {
            row.DefaultCellStyle.BackColor = Color.White;
         }
      }
   }

2.以for迴圈走訪索引,再用Rows[i]取出DataGridViewRow物件。

   public static void OddEvenColor(DataGridView dgv)
   {
      for (int i = 0; i < dgv.Rows.Count; i++)
      {
         if (i % 2 == 0)
         {
            dgv.Rows[i].DefaultCellStyle.BackColor = Color.DarkGray;
         }
         else
         {
            dgv.Rows[i].DefaultCellStyle.BackColor = Color.DarkOliveGreen;
         }
      }
   }

2018年8月9日 星期四

[Visual Studio] 移除Visual Studio方案的TFS版本控制

1.刪除所有專案中的*.vssscc,*.vspscc檔案。

2.以文字編輯器開啟*.sln方案檔。

3.刪除GlobalSection(TeamFoundationVersionControl)到EndGlobalSection之間的全部程式碼。

GlobalSection(TeamFoundationVersionControl) = preSolution
SccNumberOfProjects = 2
SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C}
SccTeamFoundationServer = http:///tfs/defaultcollection
SccLocalPath0 = .
SccProjectUniqueName1 = .csproj
SccProjectName1 =
SccLocalPath1 =
...
...
...
EndGlobalSection

4.以文字編輯器開啟所有*.csproj專案檔。

5.刪除SccProjectName、SccLocalPath、SccAuxPath、SccProvider標籤。

<SccProjectName>???</SccProjectName>
<SccLocalPath>???</SccLocalPath>
<SccAuxPath>???</SccAuxPath>
<SccProvider>???</SccProvider>

2018年7月30日 星期一

[C#] TimpSpan與格式化字串互轉

TimeSpan.ToString():將TimeSpan物件轉成格式化字串。

TimeSpan.Parse():將格式化字串轉成TimeSpan物件。

h:時間間隔中未計入天數部分的完整時數。 一位數的小時不會有前置零。

hh:時間間隔中未計入天數部分的完整時數。 一位數的小時有前置零。

m:時間間隔中未納入時數或天數部分的完整分鐘數。 一位數的分鐘不會有前置零。

mm:時間間隔中未納入時數或天數部分的完整分鐘數。 一位數的分鐘有前置零。

s:時間間隔中未納入時數、天數或分鐘數部分的完整秒數。 一位數的秒不會有前置零。

ss:時間間隔中未納入時數、天數或分鐘數部分的完整秒數。 一位數的秒有前置零。

//TimeSpan物件轉成格式化字串
TimeSpan time1 = new TimeSpan(20, 35, 10);
Console.WriteLine(time1.ToString(@"hh\:mm\:ss"));
//格式化字串轉成TimeSpan物件
TimeSpan time2 = TimeSpan.Parse("05:42:37");
Console.WriteLine(time2.ToString(@"hh\:mm\:ss"));

2018年7月20日 星期五

[網路] 301與302轉址規則差異

301與302轉址定義

301轉址又稱為301永久重新定向轉址,宣告這個網址確定改成新的網址了,舊的網址將不存在,對於搜尋引擎來說,會重新檢索新的網址及內容。302轉址則是暫時轉走,搜尋引擎仍會檢索舊頁面的網址及內容。

301與302轉址對SEO影響

301 重新導向會流失 15% 左右的網頁權重。Matt Cutts 在 2013 年確認了這個說法,當時他正在講解使用 301 重新導向,會使得連結在轉換頁面時流失部分權重。

302 重新導向並不會傳遞任何網頁權重。根據定義,302 重新導向是暫時的。所以搜尋引擎認定 302 重新導向與 301 重新導向不同。

將 HTTP 轉換至 HTTPS 規範會導致網頁權重流失。這是因為整個過程中會涉及許多301重新導向。

2018年7月12日 星期四

[C#] LINQ to Entities 中不支援所指定的型別成員 'Date' 錯誤的解決方式

Entity Framework 6 使用DbFunctions.TruncateTime(DateTime? obj),再比較日期:

var query = db.Table.Where(x => DbFunctions.TruncateTime(x.CreateTime).Value == new DateTime(2000,1,1));

Entity Framework 5以前 使用EntityFunctions.TruncateTime(DateTime? obj),再比較日期:

var query = db.Table.Where(x => EntityFunctions.TruncateTime(x.CreateTime).Value == new DateTime(2000,1,1));

2018年7月10日 星期二

[網路] 常用的Port Number

通訊埠說明
20FTP 資料埠
21FTP 控制埠
22SSH
23Telnet
25SMTP
53DNS
80HTTP
123NTP
110POP3 未加密
115SFTP
143IMAP
443HTTPS
465SMTP 加密
995POP3 加密
1433MSSQL資料庫
3306MySQL資料庫
3389RDP 遠端桌面協定
8080HTTP替代埠,Apache Tomcat