[Silverlight]DataGrid與XML以及DB的相遇 ----- Day8
在上次使用WCF來作為Silverlight控制項的資料來源,這次,我們透過DataGrid讀取XML檔案以及資料庫內的檔案。
一開始,先新增一個Silverlight專案,命名為App_D8 (如果不知道如何新增,請參考 [Silverlight]Hello Siverlight ----- Day 1)
要怎樣進行?首先,我們要先來產生假資料。
你可以到這個網址 - http://www.generatedata.com/#generator ,然後透過下列畫面中的設定:
設定好七個欄位所要的資料類型及選項、父跟子Node的名稱,以及匯出格式-XML,然後按下產生:
你就會看到它開啟新頁,內容是隨機產生的。
接下來,把整個XML內容複製起來,在App_D8專案中,新增一個Cus.xml,然後把內容貼到這個XML中,存檔:
(這邊要注意到,編碼為utf-8)
在Page.xaml中,輸入如下的Xaml Code:(筆者有透過Expression Blend 2調整控制項位置,所以會看到Blend的namespace)
<UserControl xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data" x:Class="App_D8.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="800" Height="400" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d">
<Grid x:Name="LayoutRoot" Background="White">
<data:DataGrid x:Name="myDataGrid" AutoGenerateColumns="True" Canvas.Left="10" Margin="88,16,88,104"/>
<Button x:Name="uxXmlLoad" Content="從XML抓資料" Click="uxXmlLoad_Click" Width="90" Height="30" HorizontalAlignment="Left" Margin="256,0,0,50" VerticalAlignment="Bottom" d:LayoutOverrides="Width, Height"/>
<Button x:Name="uxDBLoad" Content="從DB抓資料" Click="uxDBLoad_Click" Width="90" Height="30" Margin="398,0,312,50" VerticalAlignment="Bottom" d:LayoutOverrides="Width, Height"/>
</Grid>
</UserControl>
其中,我設定了一個DataGrid,設定其自動產生欄位的屬性為True,然後新增兩個Button,其中一個是讀取XML檔案,
另一個則是要去讀取DB中的資料內容。
我們先來寫讀取XML檔案的程式碼:
1.
加入System.Xml.Linq的參考:
2.
在Page.xaml.cs輸入下列程式碼:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Xml.Linq;
namespace App_D8
{
public partial class Page : UserControl
{
public Page()
{
InitializeComponent();
}
private void uxXmlLoad_Click(object sender, RoutedEventArgs e)
{
XDocument customersDoc = XDocument.Load("Cus.xml");
List<Customer> data = (from customer in customersDoc.Descendants("Customer")
select new Customer()
{
Level = customer.Element("Level").Value,
Name = customer.Element("Name").Value,
Age = customer.Element("Age").Value,
Sex = customer.Element("Sex").Value,
City = customer.Element("City").Value,
Address = customer.Element("Address").Value,
Quantity = customer.Element("Quantity").Value
}).ToList();
myDataGrid.ItemsSource = data;
}
private void uxDBLoad_Click(object sender, RoutedEventArgs e)
{
}
}
public class Customer
{
public string Level { get; set; }
public string Name { get; set; }
public string Age { get; set; }
public string Sex { get; set; }
public string City { get; set; }
public string Address { get; set; }
public string Quantity { get; set; }
}
}
在讀取XML檔案的Button Click事件中,我們透過LINQ的方式去讀取XML,然後將回傳的內容作為DataGrid的資料來源。
按下F5後的執行結果:
你也可以用拖拉的方式變換欄位順序:
接下來,我們要進行從DB讀取資料的作業,同樣地,我們也是到剛剛那個網址,然後將格式變更為SQL,
在SQL 選項中,依照下列方式設定(DB沒有SQL Server選項,所以只好選MySQL)
幫你產生Script:
1.
在SQL Server中執行這些Script來產生資料。
2.
利用[Silverlight]整合Silverlight與WCF ----- Day7的專案,我們需要在Day7的WCF Service中來增加一個方法。
為什麼不能在Silverlight的專案中直接存取ADO.NET的東西呢?我們來嘗試一下。
加入在C:\Windows\Microsoft.NET\Framework\v2.0.50727\的System.Data.dll參考,你會發現出現下列視窗:
這告訴我們,Silverlight的Runtime無法去編譯這個dll,所以要讀取DB,我們還是透過WCF Service來作處理。
3.
在Day7的SLWithWcf_D7.Web專案中,我們新增一個強型別的DataSet,命名為MyDs.xsd,然後新增如下的TableAdapter:
4.
接下來,在IMyWcf.cs檔案中,新增一個DataContract,叫做GetCustDataX以及一個Customers的類別:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
namespace SLWithWcf_D7.Web
{
// NOTE: If you change the interface name "IMyWcf" here, you must also update the reference to "IMyWcf" in Web.config.
[ServiceContract]
public interface IMyWcf
{
[OperationContract]
string SayHello(string userName);
[OperationContract]
List<Customer> GetCustomerData();
[OperationContract]
List<Customers> GetCustDataX(); //讀取DB的服務
}
[DataContract]
public class Customer
{
[DataMember]
public string Name;
[DataMember]
public string Address;
[DataMember]
public string sex;
}
[DataContract]
public class Customers
{
[DataMember]
public string Level { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public string Age { get; set; }
[DataMember]
public string Sex { get; set; }
[DataMember]
public string City { get; set; }
[DataMember]
public string Address { get; set; }
[DataMember]
public string Quantity { get; set; }
}
}
5.
在MyWcf.svc.cs,則是依照下列方式設定GetCustDataX方法:
這邊要注意的是,WCF Service在傳送強型別的DataTable上可能會產生問題,所以這邊我用List來作處理。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.ServiceModel.Activation;
namespace SLWithWcf_D7.Web
{
// NOTE: If you change the class name "MyWcf" here, you must also update the reference to "MyWcf" in Web.config.
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class MyWcf : IMyWcf
{
#region IMyWcf Members
public string SayHello(string userName)
{
if (DateTime.Now.Hour >= 8 && DateTime.Now.Hour < 12)
{
return "Hi, " + userName + ",現在是早上,才剛上班,不要偷懶喔!!";
}
else if (DateTime.Now.Hour >= 12 && DateTime.Now.Hour <= 17)
{
return "Hi, " + userName + ",現在是下午,在撐一下,就要下班了!!";
}
else
{
return "Hi, " + userName + ",下班就是要休息喔!!";
}
}
#endregion
#region IMyWcf Members
public List<Customer> GetCustomerData()
{
List<Customer> cus = new List<Customer>();
cus.Add(new Customer() { Name = "lolota", Address = "台北市", sex = "M" });
cus.Add(new Customer() { Name = "eva", Address = "台北市", sex = "F" });
cus.Add(new Customer() { Name = "hala", Address = "台北市", sex = "M" });
cus.Add(new Customer() { Name = "bunny", Address = "台中市", sex = "M" });
return cus;
}
#endregion
#region IMyWcf Members
public List<Customers> GetCustDataX()
{
MyDsTableAdapters.MyTestTableAdapter adapter = new SLWithWcf_D7.Web.MyDsTableAdapters.MyTestTableAdapter();
MyDs.MyTestDataTable dt = adapter.GetData();
List<Customers> li = new List<Customers>();
foreach (var item in dt)
{
li.Add(new Customers() { Level =item.Level,Name=item.Name,
Age=item.Age ,Sex=item.Sex,
City=item.City,Address=item.Address,
Quantity=item.Quantity});
}
return li;
}
#endregion
}
}
6.
按下F5執行,看看是否運作正常?如果正確,佈署到Server上,然後透過Day7的加入Service參考的方式處理,把參考命名為WCFService。
7.
然後在App_D8的Page.xaml.cs輸入下列程式碼:
private void uxDBLoad_Click(object sender, RoutedEventArgs e)
{
WCFService.MyWcfClient proxy = new App_D8.WCFService.MyWcfClient();
proxy.GetCustDataXCompleted += new EventHandler<App_D8.WCFService.GetCustDataXCompletedEventArgs>(proxy_GetCustDataXCompleted);
proxy.GetCustDataXAsync();
}
void proxy_GetCustDataXCompleted(object sender, App_D8.WCFService.GetCustDataXCompletedEventArgs e)
{
myDataGrid.ItemsSource = e.Result;
}
8.
按下F5執行:
參考來源:
http://msdn.microsoft.com/en-us/library/bb308960.aspx
http://www.generatedata.com/#generator
若WCF使用上有出現錯誤,可以參考下列網址(有可能會出現404錯誤,或是跨網域錯誤):
http://weblogs.asp.net/tolgakoseoglu/archive/2008/03/18/silverlight-2-0-and-wcf.aspx
http://www.bbits.co.uk/blog/archive/2008/09/12/debugging-wcf-services-in-silverlight-2.aspx
試煉大會,我們下次見~~
補充說明:
有讀者問說是否可以新增一列來做資料的新增,其實可以透過下列方式:
作法就是塞一個空列到資料來源,然後在綁到DataGrid物件中。
private void Button_Click(object sender, RoutedEventArgs e)
{
Customer x = new Customer { Level = "", Name = "", Age = "", Address = "", City = "", Quantity = "", Sex = "" };
List<Customer> BoundData = myDataGrid.ItemsSource as List<Customer>;
int index = 100;
BoundData.Add(x);
myDataGrid.ItemsSource = null;
myDataGrid.ItemsSource = BoundData;
myDataGrid.SelectedIndex = index + 1;
myDataGrid.BeginEdit();
myDataGrid.UpdateLayout();
}
如果您有微軟技術開發的問題,可以到MSDN Forum發問。
如果您有微軟IT管理的問題,可以到TechNet Forum發問喔。