[Silverlight]DataGrid與XML以及DB的相遇 ----- Day8

[Silverlight]DataGrid與XML以及DB的相遇 ----- Day8

上次使用WCF來作為Silverlight控制項的資料來源,這次,我們透過DataGrid讀取XML檔案以及資料庫內的檔案。

 

一開始,先新增一個Silverlight專案,命名為App_D8 (如果不知道如何新增,請參考 [Silverlight]Hello Siverlight ----- Day 1)

 

要怎樣進行?首先,我們要先來產生假資料。

你可以到這個網址 - http://www.generatedata.com/#generator ,然後透過下列畫面中的設定:

設定好七個欄位所要的資料類型及選項、父跟子Node的名稱,以及匯出格式-XML,然後按下產生:

image

 

你就會看到它開啟新頁,內容是隨機產生的。

image

 

接下來,把整個XML內容複製起來,在App_D8專案中,新增一個Cus.xml,然後把內容貼到這個XML中,存檔:

(這邊要注意到,編碼為utf-8)

image

 

在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>

 

 

 image

 

其中,我設定了一個DataGrid,設定其自動產生欄位的屬性為True,然後新增兩個Button,其中一個是讀取XML檔案,

另一個則是要去讀取DB中的資料內容。

 

我們先來寫讀取XML檔案的程式碼:

1.

加入System.Xml.Linq的參考:

image

 

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後的執行結果:

image

 

你也可以用拖拉的方式變換欄位順序:

image

 

接下來,我們要進行從DB讀取資料的作業,同樣地,我們也是到剛剛那個網址,然後將格式變更為SQL,

在SQL 選項中,依照下列方式設定(DB沒有SQL Server選項,所以只好選MySQL)

image

 

幫你產生Script:

image

 

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參考,你會發現出現下列視窗:

image

 

這告訴我們,Silverlight的Runtime無法去編譯這個dll,所以要讀取DB,我們還是透過WCF Service來作處理。

 

3.

在Day7的SLWithWcf_D7.Web專案中,我們新增一個強型別的DataSet,命名為MyDs.xsd,然後新增如下的TableAdapter:

image

 

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執行:

image

 

線上Demo

程式碼下載

 

 

參考來源:

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.vitarn.com/108.htm

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發問喔。