在Visual Studio 2013莫明地crash後,試著重新開啟它,卻一直出現以下錯誤訊息。不論是按下Yes或No,方案內的專案都無法被載入,且關閉VS時還會出現另一個錯誤訊息導致無法關閉,最後僅能透過Task Manager去強制關閉VS。
有國外開發人員也反應在VS 2012遇到一樣的問題,更新了VS 2012 Update 4後問題就不見了。最後我參考了MSDN論壇的討論解決了這個問題。作法是到%LOCALAPPDATA%\Microsoft\VisualStudio\12.0 (例如在我的Windows 8系統下為C:\Users\Pete.chen\AppData\Local\Microsoft\VisualStudio\12.0)路徑下將ComponentModelCache資料夾移除,接下來重新啟動VS便可正常運作。
January 22, 2014
January 20, 2014
.NET內建的Observer Pattern應用
在一個Windows Forms專案中,有個需求如下。
主表單有一DataGridView顯示會員資料列表,使用者點選某筆會員資料,系統會跳出一個子表單提供修改會員資料功能。更新會員資料後,主表單DataGridView裡的會員資料也隨之更新,以反應最新會員資料。
依上所述,可能的實作方式可以在主表單加入一個取得最新會員資料的方法,如LoadLatestUsers。在子表單中更新會員資料後,呼叫主表單的LoadLatestUsers以更新主表單的顯示資料。
主表單
各位也可以發現,上述的需求就如同一般所說的Publisher-Subscriber或Observer Pattern。在.NET Framework 4.0開始,內建了兩個介面IObserver<T>及IObservable<T>可供開發人員實作Observer Pattern以達到前述的需求。
子表單
主表單
以.NET Framework提供的內建介面來實作Observer Pattern,不僅讓子表單與主表單的耦合度降低,若有多個Subscriber,以此方式實作也相當簡單,而子表單也不需要知道它的Subscriber有誰,只管發送更新通知即可,Subscriber自然會作相對應的處理,只要它們都有實作IObserver<User>介面。
完整範例程式碼可至https://github.com/petekcchen/blog/tree/master/DataGridViewObserver下載。
主表單有一DataGridView顯示會員資料列表,使用者點選某筆會員資料,系統會跳出一個子表單提供修改會員資料功能。更新會員資料後,主表單DataGridView裡的會員資料也隨之更新,以反應最新會員資料。
依上所述,可能的實作方式可以在主表單加入一個取得最新會員資料的方法,如LoadLatestUsers。在子表單中更新會員資料後,呼叫主表單的LoadLatestUsers以更新主表單的顯示資料。
主表單
private void DataGridView_Users_CellMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e) { if (e.RowIndex == -1) { return; } DataGridViewRow currentRow = this.DataGridView_Users.CurrentRow; User user = currentRow.DataBoundItem as User; if (user == null) { return; } ChildForm form = new ChildForm(user); form.Owner = this; form.ShowDialog(); } public void LoadLatestUsers() { this.DataGridView_Users.DataSource = Repository.GetUsers(); }子表單
public ChildForm(User user) : this() { this._user = user; } private void ChildForm_Load(object sender, EventArgs e) { this.TextBox_FirstName.Text = this._user.FirstName; this.TextBox_LastName.Text = this._user.LastName; this.TextBox_PhoneNumber.Text = this._user.PhoneNumber; } private void Button_Update_Click(object sender, EventArgs e) { this._user.FirstName = this.TextBox_FirstName.Text; this._user.LastName = this.TextBox_LastName.Text; this._user.PhoneNumber = this.TextBox_PhoneNumber.Text; Repository.Update(this._user); MainForm mainForm = this.Owner as MainForm; mainForm.LoadLatestUsers(); this.Close(); }此一方法主要是在主表單建立一個公開方法LoadLatestUsers,在開啟子表單時,將子表單的Owner設為主表單。如此在子表單更新完資料後,取得Owner轉為主表單型別並呼叫LoadLatestUsers。以此方式實作,主要的缺點就是子表單與主表單耦合度太高,子表單需要明確知道它的Owner是誰。如果它的Owner需要有兩個表單以上該如何處理?
各位也可以發現,上述的需求就如同一般所說的Publisher-Subscriber或Observer Pattern。在.NET Framework 4.0開始,內建了兩個介面IObserver<T>及IObservable<T>可供開發人員實作Observer Pattern以達到前述的需求。
子表單
public partial class ChildForm : Form, IObservable<User> { private User _user; IObserver<User> _observer; // 省略 private void Button_Update_Click(object sender, EventArgs e) { this._user.FirstName = this.TextBox_FirstName.Text; this._user.LastName = this.TextBox_LastName.Text; this._user.PhoneNumber = this.TextBox_PhoneNumber.Text; Repository.Update(this._user); if (this._observer != null) { this._observer.OnNext(this._user); } this.Close(); } #region IObservable<User> Members public IDisposable Subscribe(IObserver<User> observer) { this._observer = observer; return null; } #endregion }子表單實作了IObservable<User>介面,上面的範例是假設Subscriber只有一個,如果有多個Subscriber可以自行修改,例如將_observer變數改為Dictionary或List型別。在會員資料更新後,呼叫IObserver<T>介面的OnNext方法以通知Subscriber(s)有更新。
主表單
public partial class MainForm : Form, IObserver<User> { // 省略 private void DataGridView_Users_CellMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e) { // 省略 ChildForm form = new ChildForm(user); form.Subscribe(this); form.ShowDialog(); } private void LoadLatestUsers() { this.DataGridView_Users.DataSource = Repository.GetUsers(); } #region IObserver<User> Members public void OnCompleted() { throw new NotImplementedException(); } public void OnError(Exception error) { throw new NotImplementedException(); } public void OnNext(User value) { this.LoadLatestUsers(); } #endregion }主表單實作了IObserver<User>介面,並在開啟子表單時,呼叫其Subscribe方法訂閱更新。當子表單更新資料後便會呼叫OnNext方法重新載入最新的會員資料。各位可以看到原本的LoadLatestUser方法已變更為私有方法。OnNext方法傳入的是單一會員資料,如果不想重新載入所有的會員資料,也可以直接更新DataGridView上該筆會員資料以免載入不必要的資料。
以.NET Framework提供的內建介面來實作Observer Pattern,不僅讓子表單與主表單的耦合度降低,若有多個Subscriber,以此方式實作也相當簡單,而子表單也不需要知道它的Subscriber有誰,只管發送更新通知即可,Subscriber自然會作相對應的處理,只要它們都有實作IObserver<User>介面。
完整範例程式碼可至https://github.com/petekcchen/blog/tree/master/DataGridViewObserver下載。
January 16, 2014
工商服務 - Junior/Senior .NET Developer(台北)
公司名稱: Asia Fusion Technology
公司網站: http://www.afusion.com/
工作職缺: Junior/Senior .NET Developer
需求人數: 5人
工作地點: 台北市內湖區瑞光路550號
徵求條件:
公司網站: http://www.afusion.com/
工作職缺: Junior/Senior .NET Developer
需求人數: 5人
工作地點: 台北市內湖區瑞光路550號
徵求條件:
- 三年以上.NET(C#)開發經驗
- 具ASP.NET MVC開發經驗
- 會使用jQuery
- 會使用至少一套測試框架(NUnit/MSTest)
- 會使用至少一套版本控制工具(Git/SVN)
- 會使用SQL Server並撰寫T-SQL或Stored Procedure
- 具物件導向基本觀念
- 具三(多)層式架構觀念
- 良好的團隊溝通能力
加分條件:
- 具Domain Driven Design經驗
- 具Design Pattern/Dependency Injection/Inversion of Control經驗
- 具Test Driven Development經驗
- 具Continuous Integration經驗
- 具Agile/Scrum經驗
- 具跨國團隊開發經驗
- 具英文溝通能力
基本福利制度:
薪資待遇: 面議
- 勞保、健保、團保、三節禮金/禮品、周休二日
- 燈光美氣氛佳,舒適的工作環境,並附有撞球桌及多項健身器材
- 自由發揮的成長空間
- 相關課程訓練及進修學習補助、進修假
- 零食、飲料不定期供應
- 不定期的聚餐、生日餐會、尾牙活動、電影欣賞、健康檢查等
- 優於勞基法的年假及請休假制度,包括全薪病假、長輩照護假、幼兒照護假等
薪資待遇: 面議
聯絡人: Jonathan
請將您的中英文履歷和過去自行撰寫過的程式碼參考寄至hrtw@afusion.com
合適者通知面試。面試分兩個階段,第一階段與台北公司Team Lead面試,合適者將與加拿大公司CTO及Architect進行第二階段面試。
January 10, 2014
Debug模式下例外丟出無法被應用程式攔截
在一Windows Forms專案中發現,編譯後的執行檔在執行某個功能時會丟出例外顯示錯誤訊息。試著以Debug模式重現問題,應用程式卻完全不會丟出例外錯誤訊息,但log檔確實有記錄到例外訊息。
加入中斷點後逐步偵錯,才在丟出例外的程式碼停止,但例外訊息只顯示在Output視窗,且沒有詳細資料,就好像被吃掉一樣。
研究了一下發現,在Visual Studio 2010選單Debug-> Exception中,Common Language Runtime Exceptions的Thrown欄位是未被勾選的。
在我的例子中,丟出的例外為System.ArgumentOutOfRangeException。可以看到這個項目是沒有被勾選的。
把Common Language Runtime Exceptions的Thrown欄位勾選,再重新執行一次Debug模式就可以看到應用程式有丟出例外錯誤訊息。
加入中斷點後逐步偵錯,才在丟出例外的程式碼停止,但例外訊息只顯示在Output視窗,且沒有詳細資料,就好像被吃掉一樣。
研究了一下發現,在Visual Studio 2010選單Debug-> Exception中,Common Language Runtime Exceptions的Thrown欄位是未被勾選的。
在我的例子中,丟出的例外為System.ArgumentOutOfRangeException。可以看到這個項目是沒有被勾選的。
把Common Language Runtime Exceptions的Thrown欄位勾選,再重新執行一次Debug模式就可以看到應用程式有丟出例外錯誤訊息。
January 7, 2014
列舉資料flattening實作
有一需求要把如下列舉物件資料做flattening後顯示為Pete,Chen,09xx123456;Claire,Chang,09xx234567;Pudding,Chen,09xx345678;Jelly,Chen,09xx4567891。也就是單一筆資料內的屬性是以逗號串接起來,而每筆資料再以分號串接起來。
首先我們使用LINQ提供的Select方法來將列舉資料中的物件project成單一字串。
private IEnumerable<User> Users { get { yield return new User() { FirstName = "Pete", LastName = "Chen", PhoneNumber = "09xx123456" }; yield return new User() { FirstName = "Claire", LastName = "Chang", PhoneNumber = "09xx234567" }; yield return new User() { FirstName = "Pudding", LastName = "Chen", PhoneNumber = "09xx345678" }; yield return new User() { FirstName = "Jelly", LastName = "Chen", PhoneNumber = "09xx456789" }; } } public class User { public string FirstName { get; set; } public string LastName { get; set; } public string PhoneNumber { get; set; } }要達到上述需求,比較苦力一點的作法就是自已寫一個method,將列舉物件資料傳入後以迴圈方式取出資料後串接,但如果要串接的列舉物件資料越多,就會需要更多相對應的method來處理。另一種方式則是利用LINQ提供的projection功能搭配string.Join來達到串接的效果。
首先我們使用LINQ提供的Select方法來將列舉資料中的物件project成單一字串。
IEnumerable<string> projected = this.Users.Select(c => string.Format("{0},{1},{2}", c.FirstName, c.LastName, c.PhoneNumber));
Assert.AreEqual("Pete,Chen,09xx123456", projected.ElementAt(0)); Assert.AreEqual("Claire,Chang,09xx234567", projected.ElementAt(1)); Assert.AreEqual("Pudding,Chen,09xx345678", projected.ElementAt(2)); Assert.AreEqual("Jelly,Chen,09xx456789", projected.ElementAt(3));project後,列舉資料的型別就變為string了。接下來只要使用string.Join將列舉資料以分號串接起來即可完成實作。
string joined = string.Join(";", projected); Assert.AreEqual("Pete,Chen,09xx123456;Claire,Chang,09xx234567;Pudding,Chen,09xx345678;Jelly,Chen,09xx456789", joined);當然也可以用一行程式碼來完成。
string joined = string.Join(";", this.Users.Select(c => string.Format("{0},{1},{2}", c.FirstName, c.LastName, c.PhoneNumber))); Assert.AreEqual("Pete,Chen,09xx123456;Claire,Chang,09xx234567;Pudding,Chen,09xx345678;Jelly,Chen,09xx456789", joined);
January 2, 2014
StatusStrip內ProgressBar靠右對齊的小技巧
StatusStrip控制項允許加入ProgressBar控制項來顯示資料存取的進度狀況。ProgressBar加入時,預設是靠左顯示,但有時我們會希望它能靠右顯示。
ProgressBar有個屬性Alignement,在屬性視窗內它的描述為Indicates whether the item aligns towards the beginning or end of the ToolStrip。乍看之下以為設定為Right,ProgressBar就可以靠右對齊,但事實上在StatusStrip的LayoutStyle屬性為Table時,這個設定不會有作用。
大部份建議的作法是在ProgressBar前加上一個空白的StatusLabel,將其Spring屬性設為True,Text屬性設為空白。如此StatusLabel會將ProgressBar擠到最右邊去。但此方法需在StatusStrip的LayoutStyle屬性為Table時才會有作用。
在研究的過程中發現另一個可行的作法是將StatusStrip的RightToLeft屬性設為True,如此ProgressBar便會從右邊開始顯示達到靠右對齊的效果。如果ProgressBar原本右邊有StatusLabel的話,會被移到ProgressBar左邊,可手動調整位置以維持版面配置。
ProgressBar有個屬性Alignement,在屬性視窗內它的描述為Indicates whether the item aligns towards the beginning or end of the ToolStrip。乍看之下以為設定為Right,ProgressBar就可以靠右對齊,但事實上在StatusStrip的LayoutStyle屬性為Table時,這個設定不會有作用。
大部份建議的作法是在ProgressBar前加上一個空白的StatusLabel,將其Spring屬性設為True,Text屬性設為空白。如此StatusLabel會將ProgressBar擠到最右邊去。但此方法需在StatusStrip的LayoutStyle屬性為Table時才會有作用。
在研究的過程中發現另一個可行的作法是將StatusStrip的RightToLeft屬性設為True,如此ProgressBar便會從右邊開始顯示達到靠右對齊的效果。如果ProgressBar原本右邊有StatusLabel的話,會被移到ProgressBar左邊,可手動調整位置以維持版面配置。
Subscribe to:
Posts (Atom)