2010年12月26日 星期日

FileSystemWatcher and network device in C#

在C#中,對於檔案的監聽,提供了一個好用的API,即是FileSystemWatcher。他的語法也非常簡單,使用方法如下。

FileSystemWatcher watch = new FileSystemWatcher();
watch.Path = @"c:\";
watch.Changed += new FileSystemEventHandler(myFileWatchEvent);
watch.EnableRaisingEvents = true;

然後再寫一個myFileWatchEvent做目錄下檔案有變動時的對應事件。

private void AppFileWatchEvent(object sender, FileSystemEventArgs e) {
    FileInfo fi = new FileInfo(e.FullPath);
    if (fi.Name.CompareTo("test.txt") == 0) {
        //file change
    }
}

這樣一來,當目錄下的test.txt有任何更動時,就會觸發事件。

然而,FileSystemWatcher有個致命的缺點就是,他無法在網路磁碟機下正常運作。如果檔案在網路磁碟機下,由自己對檔案作改動,FileSystemWatcher是可以偵測到的。但如果是被其他人改動,除非我對該目錄手動作一個refresh動作,不然FileSystemWatcher是一點反應也沒有的。

這時候就要用老方法去監看檔案改變了。這裡是用定期看檔案日期有沒有做改變。

DateTime lastModifyTime = DateTime.MinValue;

private void DoFileChange(){
    FileInfo fw = new FileInfo(@"C:\test.txt");
    if (fw.Exists) {
        if(lastModifyTime == DateTime.MinValue){
            lastModifyTime = File.GetLastWriteTime(fw.FullName);
        }

        DateTime currentModifyTime = File.GetLastWriteTime(fw.FullName);

        if (lastModifyTime < currentModifyTime) {
            //File change   
        }
        lastModifyTime = currentModifyTime;
    }
}

然後用個while迴圈包起來。

private void DoFileChangeLoop(){
    while (true) {
        DoFileChange();
        Thread.Sleep(1000);
    }
}

當然,你必須將DoFileChangeLoop放在thread裡面。

實際執行下來,耗費的系統資源還蠻少的,在可以接受的範圍之內。

GUI Thread on C#

在C#中,一般情況下,控制GUI元件時,必須要用main thread去控制。然而我們常常將運算丟至一個新的thread中,然後在運算時更新GUI的狀態。這時例外就會警告你不能這樣做。MSDN提供了delegate解法去做,但我覺得麻煩,也不夠直覺。後來參考了這裡,是使用SynchronizationContext,發現還挺好用的。使用方如下。

首先在GUI class範疇下宣告SynchronizationContext。

public partial class A:Form{
    SynchronizationContext mainSynchronizationContext;
}

接著在constructor上面,將SynchronizationContext做指定。這樣SynchronizationContext就可以抓得到現在的執行緒。

public partial class A:Form{
    public A(){
        mainSynchronizationContext = SynchronizationContext.Current;
    }
}

然後寫一個方法,負責執行GUI更新動作。label1在這裡是一個Lebel類別

public void InvokeGUI(string str) {
    mainSynchronizationContext.Post
        (
        new SendOrPostCallback
            (
            (obj)
            =>
            {
               label1.Text=(String)obj;
               
            }
            )
            ,
            str
       );
}

其中mainSynchronizationContext.Post,是非同步處理,指的是不會等待GUI就進行下一步驟。如果使用mainSynchronizationContext.Send的話,則是進行同步處理。當GUI真正動作完成才會做返回動作。script則是傳入的引數。

然後在你的thread運算時呼叫這個function,便不會拋出例外訊息了。

參考資料:
[1] (筆記) 跨執行緒存取控制項 (WPF、WinForm 通用)
[2] 深入线程,实现自定义的SynchronizationContext

第[2]有詳細說明SynchronizationContext的原理,推薦可以看看。

2010年12月19日 星期日

[PS3] God of war 3

ACT類型。

這款遊戲真是超爽快的。在畫面,音樂,系統流暢度都是無可挑剔的。場面也相當大,非常震撼。整部遊戲玩起來既像在看電影吧。謎題來說也是不難。難度的選擇上,簡單也是輕鬆就可以過了。

我在玩的時候,最常死的地方就是跳了。常常跳錯地方,不然就是想看看寶箱是不是藏在懸崖下面而跳下去。反正跳失敗重生點都是在非常近的地方,多試幾次也沒關係。

遊戲路線基本上是不能回頭的,有時發現走另一條路才能拿到寶箱,結果發現走不回去了。寶箱升級道具沒全拿也沒關係,最簡單模式幾乎不損什麼寫的。

真得很推薦這款遊戲。

God_of_War_3_GOW3Cover