公告資訊

未經授權,禁止轉載網站文章與內容。如有需要可以跟我聯絡,謝謝!!




2008年8月5日 星期二

Silverlight 2 講堂 -13:使用Timer建立圖片輪播器[程式]

        在跑馬燈的課程當中,曾經教過如何在程式中建立BitmapImage物件,以及如何動態的將圖片套用到Image控制項當中。如果你有做出前一個練習的話,相信對於這動態切換圖型的技巧應該會有印象。但這一個練習要做的是會自動循環播放照片的圖片輪播器,不像是跑馬燈是使用者用滑鼠點選之後才開始播放的。換句話說,我們必須要在表單的背景當中,建立一個新的執行緒幫我們定時觸發時間軸更換照片。

        天啊! "執行緒"! 會不會太難了一點?? 其實一點也不會。Silverlight 2當中最棒的就是內建了Base Class Library(BCL),讓開發人員不需要花太多時間就可以開發互動式的前端程式。如果你有來恆逸聽過2956等進階的課程,就可以使用.NET應用程式中多執行緒應用程式開發技巧完成這一個功能。當然,我是假定各位沒有接觸過 -- 那也沒關係,因為Silverlight 2執行環境中的BCL(後面稱為 "Silverlight 2 Library" )相對於.NET Framework來說只是一個Micro Edition(.NET ME ??),因此只要跟上我們的進度也一樣可以學會。

        開發程式之前,你可以先下載Microsoft® Silverlight™ 2 Software Development Kit Beta 2,裡面包含了Silverlight 2 Library API的說明文件,對於你開發Silverlight程式會很有幫助。在Silverlight 2 Library當中,跟.NET Framework一樣提供了System.Threading命名空間,定義了Thread等類別,可以用來建立多執行緒的程式。這一個練習中,我們要使用的是System.Threading命名空間中的Timer物件,來幫我們觸發定時的工作。

1. 使用VS 2008開發工具開啟TimerSample專案,開啟Page.xaml.cs 程式檔。

在Page.xaml.cs程式檔前面,先宣告引用System.Windows.Media.Imaging以及System.Threading命名空間:

using System.Windows.Media.Imaging;
using System.Threading;

2. 在Page類別定義中,宣告一個BitmapImage型別的陣列成員,用來暫存要輪播的六張圖片:

private BitmapImage[] _pics = {
    new BitmapImage(new Uri("1.JPG",UriKind.Relative)),
    new BitmapImage(new Uri("2.JPG",UriKind.Relative)),
    new BitmapImage(new Uri("3.JPG",UriKind.Relative)),
    new BitmapImage(new Uri("4.JPG",UriKind.Relative)),
    new BitmapImage(new Uri("5.JPG",UriKind.Relative)),
    new BitmapImage(new Uri("6.JPG",UriKind.Relative)),
                              };

3. 宣告一個整數成員變數,用來記錄目前button1所顯示的圖片在_pics陣列中的索引值,預設為零:

private int _index = 0;

4. 再宣告一個Image型別的陣列,用來記錄所有Button控制項上的Image控制項。然後在Page類別的建構函式中,將Image控制項記錄到陣列中:

private Image[] _images;

public Page()
{
        InitializeComponent();
        _images = new Image[]{ image1,image2,image3,image4 };
}

5. 在Page類別定義中加入一個MakeIndexRight方法調整顯示圖片的起始索引值:

private void MakeIndexRight()
{
    _index = (_index + 1) < 6 ? (_index + 1) : 0;
}

6. 接下來,建立一個ResetImageSource方法,根據圖片的起始索引值將新圖片套用到image控制項上:

private void ResetImageSource() {
    int index = _index;

    //要先清除圖片的參考
    foreach (Image img in _images)
    {
        img.Source = null;

    }
    foreach (Image img in _images)
    {
        img.Source = _pics[((index < 6) ? index : (index - 6))];
        index++;
    }
}

7. 接下來建立Timer定時器,首先在Page類別定義中,宣告一個Timer型別的實體變數,取名為_timer:

private Timer _timer;

8. 當UserControl載入完成時,才要建立並啟動Timer物件。因此在Page類別建構函式中註冊Loaded事件的事件處理常式:

public Page()
{
    InitializeComponent();
    _images = new Image[] { image, image1, image2, image3 };
    this.Loaded += new RoutedEventHandler(Page_Loaded);

}

9. 接著在Page_Loaded方法中,建立Timer物件,Timer的建構函式必須要傳入下面參數:

new Timer(TimerCallback委派物件, 狀態物件, 啟動前延遲時間, 間隔時間);

    其中,TimerCallback委派物件必須要參考到一個接收Object型別、沒有回傳值的方法,用來定義每次Timer啟動時所要執行的工作;而"啟動前延遲時間"和"間隔時間"的單位是毫秒。我們要設定Timer物件每4秒啟動一次,因此在Page_Loaded方法中加入程式如下:

void Page_Loaded(object sender, RoutedEventArgs e)
{
    _timer = new System.Threading.Timer(
        new System.Threading.TimerCallback(LoadPictures),
        null,0, 4000);

}

10. 最後,建立Timer物件每次啟動時,透過TimerCallback委派物件所呼叫的LoadPictures方法。根據TimerCallback委派的規格,LoadPictures方法為接收Object型別、沒有回傳值的方法。

      但是更重要的是,就是由於Timer物件執行在背景執行緒中,因此不具備有存取使用者操作介面控制項的權利,因此我們必須要將Timer物件更新使用者操作介面的工作,暫存到UI執行緒用來佇列工作項目的Dispatcher物件中(與WPF原理相同,可參考Visual C# 2008精研講座第18章)。因此,在LoadPictures方法中,我們先將啟動Scrolling時間軸的工作定義成一個匿名方法,然後透過Dispatcher物件的BeginInvoke方法,註冊到Dispatcher物件中:

void LoadPictures(object obj) {

    this.Dispatcher.BeginInvoke(
        delegate (){
            MakeIndexRight();
            ResetImageSource();
            Scorlling.Begin();
        }
     );
}

在Silverlight 2與WPF中,這一個技巧相當的重要!

11. 建置專案,然後在測試網頁中,將Silverlight控制項的Width屬性值設為680,Height屬性值設為150。

點這裡試試程式的執行結果

如果連結無法開啟,請先看下面影片:

除了Timer之外,你也可以使用其他定義在System.Threading命名空間中的物件類別產生新的執行緒。這一個練習我們就先做到這裡,完成之後你可以將圖片輪播器崁入到HTML頁面中,產生動態播放的效果。

1 則留言:

ArmstrongChang 提到...

John 你好:
我測試這些程式後發現一些問題就是
images1、 images2、 images3、 images4不存在於目前內容中
另外還有 Scrolling也不存在於目前內容中
小弟最近正在作專題 學習silverlight中
所以請John幫忙解釋一下這些問題 非常感謝!!

最新回應

Loading...

即時與版主對話


(若狀態顯示"忙碌"時,我可能無法馬上回應。你可以留下Email,我會盡快跟你聯絡,謝謝喔!!)