本文章是由機器翻譯。

線上 Silverlight

偶爾連線環境下的 Silverlight

Mark Bloodworth

下載程式碼範例

人員即時線上的世界中,或至少有些人執行,一些時間。有些時候在未來可能會有廣泛,隨時維持連線具有較多的頻寬,比必要,但不是今日。在現實情況下,我們偶而連線,偶而具有足夠的頻寬。很少並我們知道其狀態我們是在中在指定的時間。

若要設計可以在這個現實情況下提供最佳的使用者經驗的應用程式,有考慮許多架構的選擇。

智慧型用戶端、 豐富和類似的不良、 共用通用的屬性,因為它們部署在本機電腦上。為就類似它 ’s 原本就可以在沒有連線到網路的情況下執行這些應用程式。在傳統的瀏覽器架構應用程式,手,必須連線到遠端的網頁伺服器來執行。

在這些兩個多種之間有選項可不斷增加的範圍。所有提供不同的能力,以執行應用程式離線,以及有不同程度的彈性和 UI 設計的互動功能,以及它們對不同層級的安全性限制。我們會討論最新的 incarnation 偶爾連線應用隨附高度互動式的使用者經驗,並可以執行其中一個內或外的瀏覽器。我們呈現網路連線偵測沿著上載和下載資料連線時的背景工作者處理的程式碼範例。

內容

let’s 想像相關至此一討論區的一般應用程式的發展。在我們的範例啟動為 Windows 作業系統只執行一個簡單、 大型用戶端應用程式。雖然它允許使用者在離線工作時,限制的初始的解決方案變得越來越明顯:

  • 有已新增到支援多重作業系統的需求。可以支援的潛在使用者子集,第一個版本。
  • 部署問題會造成差異,在使用者基底所安裝的版本。

以支援較淺壓載解決方案,跨多重作業系統的工作] 及 [最小化部署問題的增加壓力,與應用程式被改寫成簡單、 小型用戶端,HTML 應用程式。但是,這導致另一組問題:

  • 它的使用者介面功能已限制導致較不比直覺式的經驗。
  • 它需要冗長的瀏覽器相容性測試。
  • 透過許多使用者 ’ 網路基礎結構的效能不佳。就例如大量參考資料必須填寫連同廣泛的指令碼,來參與驗證邏輯 cater 依表單所需的使用者每次下載。
  • 使用者 couldn’t 離線使用該應用程式。

清楚地,該版本 didn’t 可能使成績。

理想但 elusive 方案在這種情況下是以容易瞭解和彈性的使用者介面有豐富網際網路應用程式 (RIA)。應用程式需要讓使用者管理大量的資料,並執行非同步資料上載及資料驗證在連線時,不需要鎖定 UI。它應該支援離線工作,而且在用戶端上的資料存放區的存取。它應該整合如相機在用戶端上的硬體裝置。從 [開始] 功能表或 [應用程式圖示啟動這個理想的解決方案應該最後,— 和存在於 Web 瀏覽器的範圍以外。

Silverlight 可以提供這些需求。Silverlight 3 導出的瀏覽器的經驗的概念,這已經擴充 Silverlight 4] 中。此外,Silverlight 4 導入特定的資料夾,例如 「 我圖片 」 與硬體裝置例如網路攝影機互動功能 (使用此增強的功能的應用程式會通知應用程式需要更高的信任,而且在安裝應用程式之前,需要使用者 ’s 同意的使用者 — 受信任的應用程式有關的詳細資訊,請參閱這篇文章:msdn.microsoft.com/library/ee721083(v=VS.95)).這個本文重點將會是架構支援線上和離線工作的應用程式時所發生的常見問題。

圖 1 顯示當做很好的候選的信封後架構。


圖 1 的 候選的高階架構

一般使用者案例的案例包括:

  • 膝上型電腦與行動工作者。膝上型電腦可能有 3G 卡,或可能會連接到無線網路,在辦公室或網際網路的作用中。
  • 與桌面電腦在有限的連線能力的環境中,這類的較舊或 prefabricated 辦公大樓的使用者。

偵測網路狀態

預期偶爾連線的環境中運作的應用程式,必須能夠檢查網路連線的目前狀態。Silverlight 3 NetworkInterface.GetIsNetworkInterfaceAvailable 方法提出這項功能。這類應用程式也可以使用的網路介面的 IP 位址變更時所引發的 NetworkChange.NetworkAddressChangedEvent 進行。

因此,equipping 處理動態連接應用程式的第一個步驟是處理 [NetworkChange.NetworkAddressChangedEvent。處理這個事件明顯的地方是在應用程式類別,做為項目指向 Silverlight 應用程式。預設情況下,這個類別會實作 (對於那些以 C# 撰寫),App.xaml.cs 或 App.xaml.vb (對於那些在 VB.NET 撰寫)。在從此我們使用在 C# 中的範例。Application_StartUp 事件處理常式看起來像是 [訂閱合理的地方:

private void Application_Startup(object sender, StartupEventArgs e)
{
  NetworkChange.NetworkAddressChanged += new
    NetworkAddressChangedEventHandler(NetworkChange_ 
    NetworkAddressChanged);
  this.RootVisual = newMainPage();
}

我們需要下列 using 陳述式:

using System.Net.NetworkInformation;

NetworkChange_NetworkAddressChanged 事件處理常式包含網路偵測的肉。 這裡 ’s 範例實作:

void NetworkChange_NetworkAddressChanged(object sender, EventArgs e)
{
  this.isConnected = (NetworkInterface.GetIsNetworkAvailable());
  ConnectionStatusChangedHandler handler = 
    this.ConnectionStatusChangedEvent;
  if (handler != null)
  {
    handler(this.isConnected);
  }
}

第一個呼叫是 GetIsNetworkAvailable 來查看是否 ’s 網路連線。 在此的範例結果存入經由一的屬性公開的欄位,並引發的其他部分的應用程式使用的事件:

private bool isConnected = (NetworkInterface.GetIsNetworkAvailable());

public event ConnectionStatusChangedHandlerConnectionStatusChangedEvent;

public bool IsConnected
{
  get
  { 
    return isConnected;
  }
}

這個範例具有來偵測並處理目前的網路連線能力的基本架構。 但是,即使 GetIsNetworkAvailable 傳回 true,當電腦連線至網路 (而不是回送] 或 [通道] 介面中),網路,可能是連線,但不是會很有用。 這可以是大小寫,當電腦連線到一個路由器,但是路由器已遺失它的網際網路連線時,或當電腦連接到一個公用的 Wi-Fi 存取點,要求使用者登入,透過瀏覽器。

了解有 ’s 有效的網路連線是解決方案的健全的一部份。 Silverlight 應用程式使用的 Web 服務可能無法存取的任何數目的理由,和 ’s 偶爾連線的應用程式處理這個 eventuality 同等重要。

有許多方法來檢查 Web 服務可用。 第一方 Web 服務 — 也就是 Web 服務所控制的 Silverlight 應用程式的開發人員 — 可能會希望新增簡單的無 op 方法用來判斷可用性定期。 這不是可能的協力廠商 Web 服務,就例如或不令人滿意,逾時應該會適當地設定和處理中。 Silverlight 3 使用 Windows 通訊基礎的用戶端設定的子集 — 自動產生時使用 [加入服務參考] 工具。

儲存資料

除了能夠在網路環境中的變更作出反應,應用程式也需要處理應用程式處於離線狀態時,輸入的資料。 Microsoft 同步架構 ( msdn.microsoft.com/sync ) 是完整的平台與資料型別]、 [資料儲存]、 [通訊協定] 及 [拓樸的廣泛支援。 撰寫本文時它 ’s 不供使用 Silverlight,雖然會。 監看 MIX10 從工作階段,在 live.visitmix.com/MIX10/Sessions/SVC10 ,或讀取在 blogs.msdn.com/sync/archive/2009/12/14/offline-capable-applications-using-silverlight-and-sync-framework.aspx ,如需詳細資訊的部落。 清楚地,使用 Microsoft 同步架構會是最佳的選擇時的 Silverlight 成為可用。 在此同時需要簡單的解決方案來橋接間距。

顯著的佇列

在理想的情況下,UI 項目需要不有關是否資料儲存在本機或在定域機組中 — 而不適當通知使用者應用程式目前已離線或線上 ’s。 使用佇列是好的方法,用來建立此 UI 和資料存放區的程式碼之間的分隔。 正在處理佇列的元件必須能夠回應所佇列的新資料。 所有這些因素會造成顯著的佇列。 圖 2 顯示範例實作的顯著的佇列。

圖 2 的 一個顯著的佇列

public delegate void ItemAddedEventHandler();

public class ObservableQueue<T>
{
  private readonly Queue<T> queue = new Queue<T>();

  public event ItemAddedEventHandler ItemAddedEvent;

  public void Enqueue(T item)
  {
    this.queue.Enqueue(item);
    ItemAddedEventHandler handler = this.ItemAddedEvent;
    if (handler != null)
    {
      handler();
    }
  }

  public T Peek()
  {
    return this.queue.Peek();
  }

  public T Dequeue()
  {
    return this.queue.Dequeue();
  }

  public ArrayToArray()
  {
    return this.queue.ToArray();
  }

  public int Count
  {
    get
    {
      return this.queue.Count;
    }
  }
}

這個簡單的類別包裝標準的佇列,並加入資料時引發事件。 它 ’s 格式或將加入的資料型別不假設滿足的泛型類別。 只在有 ’s 觀察它的項目時,可觀察的佇列很有用。 在這種情況下,項目是類別,稱為 QueueProcessor。 尋找程式碼 QueueProcessor,之前,請先有 ’s 一個更多的考量:背景處理程序。 當 [QueueProcessor 會被通知,新的資料加入佇列時,它應該處理在背景執行緒上的資料,讓 UI 保持回應。 若要達成這項設計目標,System.ComponentModel 命名空間中定義的 「 BackgroundWorker] 類別是理想的。

BackgroundWorker

BackgroundWorker 是一個便利的方式,執行在背景執行緒上的作業。 它會公開兩個事件 — ProgressChanged 和 RunWorkerCompleted — 提供方法來通知 BackgroundWorker 工作 ’s 進度的應用程式。 BackgroundWorker.RunAsync 方法呼叫時,會引發 DoWork 事件。 這裡 ’s 設定一個 BackgroundWorker 的範例:

private void SetUpBackgroundWorker()
{
  backgroundWorker = new BackgroundWorker();
  backgroundWorker.WorkerSupportsCancellation = true;
  backgroundWorker.WorkerReportsProgress = true;
  backgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
  backgroundWorker.ProgressChanged += new
    ProgressChangedEventHandler(backgroundWorker_ProgressChanged);
  backgroundWorker.RunWorkerCompleted += new
    RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);
}

請注意程式碼在事件 DoWork 事件處理常式應該定期檢查,看看是否有取消暫止。 請參閱 MSDN 文件,在 msdn.microsoft.com/library/system.componentmodel.backgroundworker.dowork%28VS.95%29 以取得詳細資料。

IWorker

與 [ObservableQueue 泛用的本質,追隨很好分開進行建立與設定的 [BackgroundWorker 從工作定義。 簡單的介面 — IWorker — 如 DoWork 定義事件處理常式。 在事件處理常式簽名碼會將可讓類別實作 IWorker 介面,來報告進度,以及檢查取消擱置的 BackgroundWorker 寄件者的物件。 這裡 ’s IWorker 的定義:

public interface IWorker
{
  void Execute(object sender, DoWorkEventArgs e);
}

它 ’s 容易 indulge 設計中,並進行分色稿沒有任何需要的地方。 建立 IWorker 介面的概念是來自實務經驗。 ObservableQueue,如本文所示是一定要偶爾連線的應用程式的方案的一部份。 但是,它開啟例如從數位的相機匯入相片的其他工作也更容易實作與一個 ObservableQueue。 就例如當相片的路徑會置於一個 ObservableQueue,IWorker 的實作可以處理在背景影像。 使 [ObservableQueue 泛用和建立 IWorker 介面啟用這類情況下,仍然處理原始問題時。

處理佇列

QueueProcessor 是 [ObservableQueue 和 IWorker 實作一起做一些有用的事情繫結的類別。 處理佇列是一項 BackgroundWorker 包含設定的 [IWorker Execute 方法與 BackgroundWorker.DoWork 事件的事件處理常式後,[ItemAddedEvent 訂閱來建立。 圖 3 顯示 QueueProcessor 的範例實作。

圖 3 實作一個 QueueProcessor

public class QueueProcessor<T>
{
  private BackgroundWorker backgroundWorker;
  private readonly IWorker worker;

  public QueueProcessor(ObservableQueue<T>queueToMonitor, IWorker worker)
  {
    ((SampleCode.App)Application.Current).ConnectionStatusChangedEvent += new
       ConnectionStatusChangedEventHandler(QueueProcessor_
         ConnectionStatusChangedEvent);
    queueToMonitor.ItemAddedEvent += new
      ItemAddedEventHandler(PendingData_ItemAddedEvent);
    this.worker = worker;
    SetUpBackgroundWorker();
    if ((((SampleCode.App)Application.Current).IsConnected) && 
      (!backgroundWorker.IsBusy) 
      && (((SampleCode.App)Application.Current).PendingData.Count>0))
    {
      backgroundWorker.RunWorkerAsync();
    }
  }

  private void PendingData_ItemAddedEvent()
  {
    if ((((SampleCode.App)Application.Current).IsConnected) && 
      (!backgroundWorker.IsBusy))
    {
      backgroundWorker.RunWorkerAsync();
    }
  }

  private void SetUpBackgroundWorker()
  {
    backgroundWorker = new BackgroundWorker();
    backgroundWorker.WorkerSupportsCancellation = true;
    backgroundWorker.WorkerReportsProgress = true;
    backgroundWorker.DoWork += new DoWorkEventHandler(this.worker.Execute);
    backgroundWorker.ProgressChanged += new
      ProgressChangedEventHandler(backgroundWorker_ProgressChanged);
    backgroundWorker.RunWorkerCompleted += new
      RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);
  }

  private void backgroundWorker_RunWorkerCompleted(object sender,
    RunWorkerCompletedEventArgs e)
  {
    if (e.Cancelled)
    {
      // Handle cancellation
    }
      else if (e.Error != null)
      {
        // Handle error
      }
    else
    {
      // Handle completion if necessary
    }
  }

  private void backgroundWorker_ProgressChanged(object sender, 

    ProgressChangedEventArgs e)
  {
     // Raise event to notify observers
  }

  private void QueueProcessor_ConnectionStatusChangedEvent(bool isConnected)
  {
    if (isConnected)
    {
      if (!backgroundWorker.IsBusy)
      {
        backgroundWorker.RunWorkerAsync();
      }
    }
    else
    {
      backgroundWorker.CancelAsync();
    }
  }
}

圖 3 中的範例程式碼會離開實作一些例如處理錯誤,為讀取器的練習 BackgroundWorker ’s] 功能。 如果目前連接的應用程式,並在 BackgroundWorker 還不忙碌處理佇列時,會叫用 RunAsync 方法。

UploadWorker

QueueProcessor 的建構函式需要一項 IWorker 的就說表示,具體實作所需的上載資料到定域機組。 UploadWorker 似乎合理的這類的類別名稱。 圖 4 顯示範例實作。

圖 4 上載資料至 [雲霧

public class UploadWorker :  IWorker
{
  public override void Execute(object sender, DoWorkEventArgs e)
  {
    ObservableQueue<DataItem>pendingData = 
      ((SampleCode.App)Application.Current).PendingData;
    while (pendingData.Count>0)
    {
      DataItem item = pendingData.Peek();
      if (SaveItem(item))
      {
        pendingData.Dequeue();
      }
    }
  }

  private bool SaveItem(DataItem item)
  {
    bool result = true;
    // Upload item to webservice
    return result;
  }
}

圖 4,Execute 方法上載至佇列的項目。 如果它們 can’t 會上載,它們保留在佇列中。 請注意,如果是必要的存取權,BackgroundWorker — 比方就說來報告進度] 或 [檢查擱置取消 — 寄件者物件是在 BackgroundWorker。 如果結果指派給電子,DoWorkEventArgs,[結果] 屬性將會使用 RunWorkerCompleted 事件處理常式中。

隔離儲存區

將資料放入佇列,並只傳送資料到 Web 服務連線 (讓它可以儲存在定域機組) 時正常,提供應用程式永遠不會關閉。 應用程式就會關閉資料會保留在佇列中擱置,策略需要儲存該資料,直到下一步載入應用程式。 Silverlight 提供此種狀況的隔離儲存區。

隔離儲存區是虛擬檔案系統供 Silverlight 應用程式,讓本機儲存的資料。 它可以儲存有限的 (預設的限制值是 1 MB) 的資料,但應用程式可以向使用者要求更多的空間。 在我們的範例中序列化至隔離儲存區佇列會儲存應用程式工作階段之間的佇列狀態。 的 [圖 5] 所示,簡單的類別稱為 QueueStore 會執行的一輪。

圖 5 序列化至隔離儲存區的佇列

public class QueueStore
{
  private const string KEY = "PendingQueue";
  private IsolatedStorageSettings appSettings = 
    IsolatedStorageSettings.ApplicationSettings;

  public void SaveQueue(ObservableQueue<DataItem> queue)
  {
    appSettings.Remove(KEY);
    appSettings.Add(KEY, queue.ToArray());
    appSettings.Save();
  }

  public ObservableQueue<DataItem>LoadQueue()
  {
    ObservableQueue<DataItem> result = new ObservableQueue<DataItem>();
    ArraysavedArray = null;

    if (appSettings.TryGetValue<Array>(KEY, out savedArray))
    {
      foreach (var item in savedArray)
      {
        result.Enqueue(item as DataItem);
      }
    }

  return result;
  }
}

假設佇列中的項目是可序列化的 QueueStore 會啟用儲存和載入佇列。在 App.xaml.cs Application_Exit 方法和 Load 方法的 App.xaml.cs Application_Startup 方法中呼叫 Save 方法,可讓應用程式儲存工作階段之間的狀態。

DataItem 型別的已加入佇列的項目。這是代表資料的簡單類別。稍微更豐富的資料模型的情況下 DataItem 可能會保留一個簡單的物件 Graph。在更複雜的案例 DataItem 可能會繼承其他類別的基底類別。

擷取資料

一個應用程式有時只連接時,可以使用它必須有某種方式的快取在本機上的資料。第一個考量是需要的資料應用程式的工作集大小。在簡單的應用程式可能會讓本機的快取,以包含應用程式所需要的所有資料。就例如取用 RSS 摘要的簡單的讀取器應用程式可能需要快取只摘要和使用者喜好設定。其他的應用程式可能太大的工作集,或只是可能太難預測的資料需要的使用者,可有效地增加資料的工作集大小。

簡單的應用程式是一個簡單的起點。可以在應用程式啟動時下載整個如使用者的喜好設定應用程式的工作階段所需的資料,並保留在記憶體中。應該由使用者變更此資料,可套用先前所討論的上載策略。但是,這種方法會假設應用程式將連線在啟動,這可能不是大小寫。隔離儲存區會再一次在的答案,並呈現稍早的範例將 cater 到的呼叫,以下載資料的伺服器版本,在適當的地方加上這種情況下。請記住,使用者可能會有兩個的工作上安裝應用程式 PC 和家庭的 PC 讓使用者返回明顯的延遲之後應用程式時,可能是適當的時間。

另一種情況可能會牽涉到正在顯示相對靜態的資料如新聞的簡單應用程式。可以套用類似的策略:下載資料時可能、 保留在記憶體中,隔離儲存區來保存在應用程式關閉 (並重新載入從隔離儲存區在啟動時)。一旦連接可用時可失效並重新整理快取的資料。連線時可使用多個幾分鐘,應用程式應該定期重新整理資料,例如新聞。如先前討論 UI 應該不知道這項背景工作。

下載新聞的情況下開始點是簡單的 NewsItem 類別:

public class NewsItem
{
  public string Headline;
  public string Body;

  public override stringToString()
  {
    return Headline;
  }
}

這個類別會太過簡化範例的方便和 ToString 會被覆寫以輕鬆將繫結至使用者介面中。 若要將下載的新聞簡單的存放庫類別,下載新聞在背景,這是必要, 的 圖 6 所示。

圖 6 儲存已下載的新聞中存放庫類別

public class Repository
{
  private ObservableCollection<NewsItem> news = 
    new ObservableCollection<NewsItem>();
  private DispatcherTimer timer = new DispatcherTimer();
  private const int TIMER_INTERVAL = 1;

public Repository()
{
  ((SampleCode.App)Application.Current).ConnectionStatusChangedEvent += 
    new ConnectionStatusChangedHandler(Repository_
    ConnectionStatusChangedEvent);
  if (((SampleCode.App)Application.Current).IsConnected)
  {
    RetrieveNews();
    StartTimer();
  }
}

private void Repository_ConnectionStatusChangedEvent(bool isConnected)
{
  if (isConnected)
  {
    StartTimer();
  }
  else
  {
    StopTimer();
  }
}

private void StopTimer()
{
  this.timer.Stop();
}

private void StartTimer()
{
  this.timer.Interval = TimeSpan.FromMinutes(1);
  this.timer.Tick += new EventHandler(timer_Tick);
  this.timer.Start();
}

voidtimer_Tick(object sender, EventArgs e)
{
  if (((SampleCode.App)Application.Current).IsConnected)
  {
    RetrieveNews();
  }
}

private void RetrieveNews()
{
  // Get latest news from server
  List<NewsItem> list = GetNewsFromServer();
  if (list.Count>0)
  {
    lock (this.news)
    {
      foreach (NewsItem item in list)
      {
        this.news.Add(item);
      }
    }
  }
}

private List<NewsItem>GetNewsFromServer()
{
  // Simulate retrieval from server
  List<NewsItem> list = new List<NewsItem>();
  for (int i = 0; i <5; i++)
  {
    NewsItemnewsItem = new NewsItem()
    { Headline = "Something happened at " + 
        DateTime.Now.ToLongTimeString(),
        Body = "On " + DateTime.Now.ToLongDateString() + 
        " something happened.  We'll know more later." };
      list.Add(newsItem);
    }
    return list;
  }

  public ObservableCollection<NewsItem> News
  {
    get
    {
      return this.news;
    }
    set
    {
      this.news = value;
    }
  }
}

圖 6,新聞的擷取是為了保持簡潔模擬。存放庫類別到 [ConnectionStatusChangedEvent 訂閱,並當連接,使用一個 DispatcherTimer 擷取新聞,在指定的時間間隔。一個 DispatcherTimer 的 ObservableCollection 搭配用於啟用簡單資料繫結。[DispatcherTimer 整合發送器] 佇列,因此它會在 UI 執行緒上執行。更新的 ObservableCollection 的效果是,就會自動更新繫結的控制項在 UI 中,這是理想的下載新聞的情況下,就會引發事件。一個 System.Threading.Timer 在 Silverlight,可以使用,但是它 doesn’t 在 UI 執行緒上執行。在這種情況下存取物件在 UI 執行緒上的任何作業需要使用 Dispatcher.BeginInvoke 呼叫。

若要使用儲存機制需要只在 App.xaml.cs 屬性。指定存放庫訂閱其建構函式中 ConnectionStatusChangedEvent、 具現化它最佳的位置是在 [Application_StartupeventinApp.xaml.cs。

’s 不太可能使用者以外的任何人會變更的資料,例如使用者偏好設定,應用程式時離線,雖然在各種裝置上相同的使用者所使用的應用程式的情況下 ’s 當然是可能的。如新聞報導的資料也會不是用來變更。這表示快取的資料很可能是有效,且有可能不會在重新連線時同步處理的問題。但是,易變動的資料的情況下以不同的方法可能會需要。就例如,它可能會使讓他可以適當地回應上次擷取資料時,通知使用者有意義。如果應用程式需要動態的資料為基礎的決策,到期的規則將會需要附有所需的資料不適用,因為應用程式正在離線使用者的通知。

如果可以變更資料,比較時,它已變更並將啟用在許多情況下的衝突解決。就例如樂觀的方法會假設最新版本最有效,且任何的發生衝突,因此即贏得但您也可以決定要解決衝突,根據更新資料。應用程式拓樸和使用方式案例的知識是正確的方法的關鍵。在衝突版本 can’t — 或 shouldn’t — 來解決,應儲存的這種版本的記錄檔與適當的使用者接受通知,讓它們可以讓一個 judgement。

您也需要考慮找出同步處理邏輯的位置。最簡單的結論是,它也可以作為橋樑之間有衝突的版本應該位於它的伺服器上 — 在本例中 [UploadWorker 需要次要的修改,讓它將 DataItem 更新至最新的伺服器版本。如先前所述的 Microsoft 同步架構會最後處理的許多這些的問題讓開發人員可以專注於應用程式定義域。

組合此組件

所有組件討論,使用簡單的 Silverlight 應用程式,會探討這些功能在偶爾連線的環境中很容易就能建立。圖 7 顯示這類應用程式的螢幕擷取畫面。


圖 7 的 Demonstrating 網路狀態及佇列的範例應用程式

圖 7 範例,Silverlight 應用程式正在執行瀏覽器不足。指定偶爾連線的應用程式的本質,’s 可能有許多會執行瀏逾時-的-覽器,因為 ’re 給使用者從 [開始] 功能表和桌面能夠方便存取,而且不論網路連線可以執行。一個的瀏覽器的內容中執行的 Silverlight 應用程式在相對的地需要網路連線,因此它所在的 Web 伺服器可以提供 Web 網頁和 Silverlight 應用程式。

這個簡單的使用者介面,在 圖 7 幾乎肯定不在行,在 [設計] 得獎原因就能獲勝時提供方法,以執行範例程式碼。除了顯示目前的網路狀態,有輸入資料與清單方塊,繫結至儲存機制的 [新聞] 屬性的欄位。範例建立螢幕的 XAML 的 [圖 8] 所示。的 圖 9 所示的程式碼後置。

圖 8 的 範例應用程式 UI 的 XAML

<UserControl x:Class="SampleCode.MainPage" 
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" 
  xmlns:dataInput="clr-namespace:System.Windows.Controls;
    assembly=System.Windows.Controls.Data.Input" 
    Width="400" Height="300">
      <Grid x:Name="LayoutRoot" Background="White" ShowGridLines="False">
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="12" />
          <ColumnDefinition Width="120" />
          <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
          <RowDefinition Height="12" />
          <RowDefinition Height="64" />
          <RowDefinition Height="44" />
          <RowDefinition Height="34" />
          <RowDefinition Height="34" />
          <RowDefinition Height="100" />
        </Grid.RowDefinitions>
        <Ellipse Grid.Row="1" Grid.Column="1" Height="30" HorizontalAlignment="Left" 
          Name="StatusEllipse" Stroke="Black" StrokeThickness="1" 
          VerticalAlignment="Top" Width="35" />
        <Button Grid.Row="4" Grid.Column="1" Content="Send Data" Height="23" 
          HorizontalAlignment="Left" Name="button1" VerticalAlignment="Top" 
          Width="75" Click="button1_Click" />
        <TextBox Grid.Row="2" Grid.Column="2" Height="23" HorizontalAlignment="Left" 
          Name="VehicleTextBox" VerticalAlignment="Top" Width="210" />
        <TextBox Grid.Row="3" Grid.Column="2" Height="23" HorizontalAlignment="Left" 
          Name="TextTextBox" VerticalAlignment="Top" Width="210" />
        <dataInput:Label Grid.Row="2" Grid.Column="1" Height="28" 
          HorizontalAlignment="Left" Name="VehicleLabel" VerticalAlignment="Top" 
          Width="120" Content="Title" />
        <dataInput:Label Grid.Row="3" Grid.Column="1" Height="28" 
          HorizontalAlignment="Left" Name="TextLabel" VerticalAlignment="Top" 
          Width="120" Content="Detail" />
        <ListBox Grid.Row="5" Grid.Column="1" Grid.ColumnSpan="2" Height="100" 
          HorizontalAlignment="Left" Name="NewsListBox" 
          VerticalAlignment="Top" Width="376" />
      </Grid>
</UserControl>

圖 9 的 程式碼後置的範例應用程式的使用者介面

public delegate void DataSavedHandler(DataItem data);

public partial class MainPage : UserControl
{
  private SolidColorBrush STATUS_GREEN = new SolidColorBrush(Colors.Green);
  private SolidColorBrush STATUS_RED = new SolidColorBrush(Colors.Red);

  public event DataSavedHandlerDataSavedEvent;

  public MainPage()
  {
    InitializeComponent();
    ((SampleCode.App)Application.Current).ConnectionStatusChangedEvent += new
      ConnectionStatusChangedHandler(MainPage_ConnectionStatusChangedEvent);
    IndicateStatus(((NetworkStatus.App)Application.Current).IsConnected);
    BindNews();
  }

  private void MainPage_ConnectionStatusChangedEvent(bool isConnected)
  {
    IndicateStatus(isConnected);
  }

  private void IndicateStatus(bool isConnected)
  {
    if (isConnected)
    {
      StatusEllipse.Fill = STATUS_GREEN;
    }
    else
    {
      StatusEllipse.Fill = STATUS_RED;
    }
  }

  private void BindNews()
  {
    NewsListBox.ItemsSource = 
      ((SampleCode.App)Application.Current).Repository.News;
  }

  private void button1_Click(object sender, RoutedEventArgs e)
  {
    DataItem dataItem = new DataItem
    {
      Title = this.TitleTextBox.Text,
      Detail = this.DetailTextBox.Text
    };
    DataSavedHandler handler = this.DataSavedEvent;
    if (handler != null)
    {
      handler(dataItem);
    }

    this.TitleTextBox.Text = string.Empty;
    this.DetailTextBox.Text = string.Empty;
  }
}

圖 9 類別會引發事件,表示儲存資料。(在此案例 App.xaml.cs) 的觀察者訂閱這個事件,並將資料放在 ObservableQueue。

新的類別的應用程式

只有一些情況下,連線的應用程式的 Silverlight 支援 」 可以讓應用程式的新類別。這類應用程式引入新要求開發人員認為有關連線時,應用程式應該如何運作,以及當中斷連線時的考量。本文提供這些考量,並提供策略和範例程式碼處理它們。就說提供存在於有時連線的世界中的案例的廣度,範例可以只能做為起始點。

Mark Bloodworth* 是架構設計人員,在 [開發人員] 和 [平台宣導小組在 Microsoft] 中他運作方式用與公司的創新的專案。之前要聯結的 Microsoft,他已經在 BBC 全球,他用來領導小組負責架構和系統分析主要方案架構設計人員。大部分的他的工作已經被著重使用 Microsoft 的技術特別是 Microsoft.NET Framework 有點 Java 中擲回良好的量值。他會部落格保留在 remark.wordpress.com*

Dave Brown 曾 Microsoft 九年以上,最初的 Microsoft 顧問服務],在 [網際網路相關的技術。他目前適用於開發人員和在英國的平台宣導小組為 Microsoft 技術中心的架構設計人員。在此的角色,他會分割他商務分析客戶的案例的設計方案的架構和管理和開發解決方案概念證明的程式碼之間的時間。 drdave.co.uk/blog 在找不到他的部落格

感謝至下列技術專家:Ashish Shetty