2012年3月24日 星期六

[Silverlight] AutoCompleteBox技巧演示(一):透過非同步資料存取方式動態設定AutoCompleteBox的資料源

本文章是要展示如何利用WCF資料存取服務,以非同步方式動態設定AutoCompleteBox的資料源。由於使用非同步存取資料會有時間上的延誤,當介面載入後並不一定能及時提供資料源予AutoCompleteBox,故此我們在考慮介面設計時必須先決定是否接受延誤所帶來的影響。或是加入ProgressBar去控制此問題。

而AutoCompleteBox的作用是輔助使用者去加快輸入資料予欄位上,故此不需考慮能否立刻提供資料源予AutoCompleteBox。

基於使用WCF服務的關係,本示範中在後台.Web上新增了Model資料夾,並增加了一個Patient物件以非同步資料存取方式供應病人資料予前台。同時新加了Service1.svc檔案去訂立條約。
專案結構如下圖:


Patient物件的程式碼

   1:  using System.Runtime.Serialization; 
   2:   
   3:  namespace SlAutoCompleteBox1.Web.Model
   4:  {
   5:      [DataContract(Namespace = "")]
   6:      public class Patient
   7:      {
   8:          [DataMember]
   9:          private int patientID;
  10:          [DataMember]
  11:          private string name;
  12:   
  13:          public Patient(int PatientID, string Name)
  14:          {
  15:              patientID = PatientID;
  16:              name = Name;
  17:          }
  18:          
  19:          public int PatientID { get { return patientID; } set { patientID = value; } }
  20:          public string Name { get { return name; } set { name = value; } }
  21:      }
  22:  }

Service1.svc檔案的程式碼
   1:  using System.Collections.Generic;
   2:  using System.Collections.ObjectModel;
   3:  using System.Linq;
   4:  using System.ServiceModel;
   5:  using System.ServiceModel.Activation;
   6:  using SlAutoCompleteBox1.Web.Model;
   7:   
   8:  namespace SlAutoCompleteBox1.Web
   9:  {
  10:      [ServiceContract(Namespace = "")]
  11:      [SilverlightFaultBehavior]
  12:      [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
  13:      public class Service1
  14:      {
  15:          [OperationContract]
  16:          public List<string> GetPatientList()
  17:          {
  18:              ObservableCollection<Patient> patientList= new ObservableCollection<Patient>();
  19:              // 新增四筆記錄到Patient類別,該類別用作ComboBox的選項來源       
  20:              patientList.Add(new Patient(1, "John"));
  21:              patientList.Add(new Patient(2, "Sam"));
  22:              patientList.Add(new Patient(3, "Barry"));
  23:              patientList.Add(new Patient(4, "Ken"));
  24:   
  25:              var patientNameList = from p in patientList select p.Name;
  26:   
  27:              return patientNameList.ToList();          
  28:          }     
  29:      }
  30:  }


前台方面,以下是MainPage.xaml內的程式碼,我們可以看到AutoCompleteBox是位於CellEditingTemplate內。而CellTemplate 與CellEditingTemplate都是繫結PatientName屬性來刷新對應值。
   1:  <UserControl x:Class="SlAutoCompleteBox1.MainPage"
   2:      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   5:      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
   6:      mc:Ignorable="d"
   7:      d:DesignHeight="300" d:DesignWidth="400" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">
   8:   
   9:      <Grid x:Name="LayoutRoot" Background="White">
  10:          <sdk:DataGrid AutoGenerateColumns="False" HorizontalAlignment="Left" 
  11:                        Margin="24,12,0,0" Name="dataGrid1" VerticalAlignment="Top" Width="364" 
  12:                        Height="232" DataContext="{Binding}" AreRowGroupHeadersFrozen="True">
  13:              <sdk:DataGrid.Columns>
  14:                  <sdk:DataGridTemplateColumn CanUserReorder="True" CanUserResize="True" CanUserSort="True" Width="Auto" Header="PATIENT NAME" >
  15:                      <sdk:DataGridTemplateColumn.CellTemplate>
  16:                          <DataTemplate>
  17:                              <TextBlock Text="{Binding PatientName,Mode=TwoWay}" Height="23" HorizontalAlignment="Left" Margin="10,10,0,0" Name="textBlock1" VerticalAlignment="Top" />
  18:                          </DataTemplate>
  19:                      </sdk:DataGridTemplateColumn.CellTemplate>
  20:                      <sdk:DataGridTemplateColumn.CellEditingTemplate>
  21:                          <DataTemplate>
  22:                              <sdk:AutoCompleteBox Name="AutoCompleteBox" Loaded="AutoCompleteBox_Loaded" Text="{Binding PatientName,Mode=TwoWay}" ValueMemberBinding="{Binding}" />
  23:                          </DataTemplate>
  24:                      </sdk:DataGridTemplateColumn.CellEditingTemplate>
  25:                  </sdk:DataGridTemplateColumn>
  26:                  <sdk:DataGridTextColumn Binding="{Binding DiagnosisResult,Mode=TwoWay}" CanUserReorder="True" CanUserResize="True" CanUserSort="True" Header="Diagnosis Result" Width="Auto" />
  27:              </sdk:DataGrid.Columns>
  28:          </sdk:DataGrid>
  29:      </Grid>
  30:  </UserControl>

而以下是MainPage.xaml背後cs檔案的程式碼,首先在MainPage()載入介面時加入Service1Client以非同步資料存取後台Patient物件。然後儲存於patient_Name_List這個字串集合。另一方面,AutoCompleteBox 是透過AutoCompleteBox_Loaded事件把patient_Name_List這個字串集合繫結到AutoCompleteBox 的資料源。
   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.ComponentModel;
   4:  using System.Linq;
   5:  using System.Windows;
   6:  using System.Windows.Controls;
   7:  using SlAutoCompleteBox1.ServiceReference1;
   8:   
   9:  namespace SlAutoCompleteBox1
  10:  {
  11:      public partial class MainPage : UserControl
  12:      {
  13:          List<string> patient_Name_List;
  14:   
  15:          public MainPage()
  16:          {            
  17:              InitializeComponent();                 
  18:              
  19:              Service1Client proxy = new Service1Client();
  20:              proxy.GetPatientListCompleted += new EventHandler<GetPatientListCompletedEventArgs>(proxy_GetPatientListCompleted);
  21:              proxy.GetPatientListAsync();
  22:   
  23:              // 新增三筆Diagnosis記錄到DataGrid
  24:              List<Diagnosis> DiagnosisList = new List<Diagnosis>();
  25:              DiagnosisList.Add(new Diagnosis());
  26:              DiagnosisList.Add(new Diagnosis());
  27:              DiagnosisList.Add(new Diagnosis());
  28:   
  29:              dataGrid1.ItemsSource = DiagnosisList;            
  30:          }
  31:   
  32:          private void proxy_GetPatientListCompleted(object sender, GetPatientListCompletedEventArgs e)
  33:          {
  34:              //非同步資料存取結果儲存於patient_Name_List的字串集合
  35:              patient_Name_List = e.Result.ToList(); 
  36:          }
  37:   
  38:          private void AutoCompleteBox_Loaded(object sender, RoutedEventArgs e)
  39:          {
  40:              //提供資料源給AutoCompleteBox
  41:              ((AutoCompleteBox)sender).ItemsSource = patient_Name_List;
  42:              ((AutoCompleteBox)sender).FilterMode = AutoCompleteFilterMode.Contains;  
  43:          }        
  44:      }
  45:   
  46:      public class Diagnosis : INotifyPropertyChanged
  47:      {
  48:          public event PropertyChangedEventHandler PropertyChanged;
  49:          private string patientName;
  50:          private string diagnosisResult;
  51:   
  52:          public Diagnosis()   // 提供給DataGrid的資料來源類別
  53:          {         
  54:              diagnosisResult = null;
  55:          }
  56:   
  57:          public string PatientName
  58:          {
  59:              get { return patientName; }
  60:              set
  61:              {
  62:                  patientName = value; 
  63:                  NotifyPropertyChanged("PatientName");
  64:              }
  65:          }
  66:   
  67:          public string DiagnosisResult { get { return diagnosisResult; } set { diagnosisResult = value; NotifyPropertyChanged("DiagnosisResult"); } }
  68:   
  69:          private void NotifyPropertyChanged(String info)
  70:          {
  71:              if (PropertyChanged != null)       
  72:                  PropertyChanged(this, new PropertyChangedEventArgs(info));       
  73:          }
  74:      }
  75:  }

完整程式下載地址:
https://docs.google.com/open?id=0BxRiNrIXEFArWXUtZzdvNnZRQ3FyWXlWem11WE9Pdw

沒有留言:

張貼留言