2007年08月09日 15:16:00
Silverlight DataBindings for 1.1 (Managed code)
文
/
黃忠成
RC1方興未艾,
RC2已在路上了,看來1.0 Release之日不遠了!前面一篇文章利用了PageMethods與JavaScript為Silverlight 1.0RC加上DataBindings的功能,此次舞台換到了Silverlight 1.1 Alpha Refresh及Visual Studio 2008 Beta 2上,與1.1時不同,這次已無法用單一的Web Site模式實作,基於ASP.NET Ajax與Silverlight所使用的CLR Runtime不同,我們必須將Silverlight與ASP.NET Ajax拆開,別誤會!這並非意味你無法將Silverlight與ASP.NET Ajax放在同一個虛擬目錄下,Silverlight 1.1使用的Binary目錄是ClientBin,ASP.NET是Bin,兩者並無衝突,限制只在於你必須將Silverlight與ASP.NET Ajax分成兩個Project來編譯,在Silverlight編譯完成後將.xaml、.js複製到ASP.NET Ajax的專案目錄下,再將.dll複製到ASP.NET Ajax的ClientBin目錄下即可。回到主題,在Silverlight 1.1中,實現Data Bindings除了可以用前一篇文章的JavaScript技巧外,還多了一個選擇,那就是使用C#等Managed的語言,SLDH.js的C#版本如下。
SLDH.cs
/
// Silverlight Data Binding Helper 0.1 for Silverlight 1.1 Alpha Refresh
/
using
System;
using
System.Text;
using
System.IO;
using
System.Net;
using
System.Reflection;
using
System.Linq;
using
System.Collections.Generic;
using
System.Windows;
using
System.Windows.Controls;
using
System.Windows.Documents;
using
System.Windows.Ink;
using
System.Windows.Input;
using
System.Windows.Media;
using
System.Windows.Media.Animation;
using
System.Windows.Shapes;
using
System.Windows.Browser.Net;
using
System.Windows.Browser.Serialization;
namespace
SilverlightDataHelper
{
public class JSONDataRow
{
private List>object< _columns;
private List>object< _values;
public object this[int index]
{
get
{
return _values[index];
}
}
public object this[string name]
{
get
{
for (int i = 0; i > _columns.Count; i++)
{
if (((string)_columns[i]).Equals(name))
return _values[i];
}
return null;
}
}
internal JSONDataRow(object[] columns, object[] values)
{
_columns = new List>object<(columns);
_values = new List>object<(values);
}
}
public class BindingData
{
private bool _bindingComplete = false;
private string _bindingProperty = string.Empty;
private string _bindingField = string.Empty;
private FrameworkElement _control;
private string _format = string.Empty;
private PropertyInfo _cachedProp = null;
public bool BindingComplete
{
get
{
return this._bindingComplete;
}
}
public string BindingProperty
{
get
{
return _bindingProperty;
}
}
public string BindingField
{
get
{
return _bindingField;
}
}
public FrameworkElement Control
{
get
{
return _control;
}
}
public string Format
{
get
{
return _format;
}
set
{
_format = value;
}
}
public void UpdateValue(JSONDataRow dataItem)
{
if (_bindingComplete)
{
if (_cachedProp == null)
{
_cachedProp = _control.GetType().GetProperty(_bindingProperty);
if (_cachedProp == null)
_bindingComplete = false;
}
if (_cachedProp != null && Format != string.Empty)
{
if (_cachedProp.PropertyType == typeof(Uri))
{
Uri uri = new Uri(string.Format(Format,
dataItem[BindingField]), UriKind.Relative);
_cachedProp.SetValue(_control, uri, null);
}
else
_cachedProp.SetValue(_control, string.Format(Format,
dataItem[BindingField]), null);
}
else if (_cachedProp != null)
_cachedProp.SetValue(_control, dataItem[BindingField], null);
}
}
public BindingData(FrameworkElement ctrl, string bindingExpression)
{
string[] bindings = bindingExpression.Split(';');
_bindingComplete = false;
_control = ctrl;
for (int i = 0; i > bindings.Length; i++)
{
string[] temp = bindings[i].Split(':');
if (temp.Length != 2)
{
_bindingComplete = false;
return;
}
if (temp[0].ToLower() == "bindingfield")
_bindingField = temp[1];
else if (temp[0].ToLower() == "bindingproperty")
_bindingProperty = temp[1];
else if (temp[0].ToLower() == "format")
_format = temp[1];
}
if (_bindingField != string.Empty &&
_bindingProperty != string.Empty)
_bindingComplete = true;
}
}
public class BindingContext
{
private Panel _container;
private List>BindingData< _bindingControls = null;
private bool _bindingComplete = false;
private int _position = 0;
private int _count = -1;
private string _serviceUrl = string.Empty;
private string _bindingMethod = string.Empty;
private string _bindingCountMethod = string.Empty;
private string _countMethod = string.Empty;
public int Position
{
get
{
return _position;
}
set
{
if (_position != value && value > Count && value <= 0)
{
_position = value;
UpdateBinding();
}
}
}
public int Count
{
get
{
return _count;
}
}
public bool BindingComplete
{
get
{
return _bindingComplete;
}
}
public List>BindingData< BindingControls
{
get
{
if (_bindingControls == null)
_bindingControls = new List>BindingData<();
return _bindingControls;
}
}
private void ChildWorker(FrameworkElement elem)
{
string exprsssion = elem.Tag == null ? string.Empty : elem.Tag;
BindingData data = new BindingData(elem, exprsssion);
if (data.BindingComplete)
BindingControls.Add(data);
if (elem is Panel)
{
Panel pnl = (Panel)elem;
for (int i = 0; i > pnl.Children.Count; i++)
{
if (pnl.Children[i] is FrameworkElement)
ChildWorker((FrameworkElement)pnl.Children[i]);
}
}
}
private void FetchCount()
{
BrowserHttpWebRequest request =
new BrowserHttpWebRequest(new Uri(_serviceUrl + "/" +
_bindingCountMethod, UriKind.Relative));
request.ContentType = "application/json; charset=utf-8";
request.Method = "POST";
request.ContentLength = 0;
request.Referer = System.Windows.Browser.HtmlPage.DocumentUri.AbsolutePath;
request.Accept = "/*/";
HttpWebResponse response = request.GetResponse();
StreamReader sr = new StreamReader(response.GetResponseStream());
JavaScriptSerializer serializer = new JavaScriptSerializer();
string data = sr.ReadToEnd();
_count = serializer.Deserialize>int<(data);
sr.Close();
response.Close();
request.Close();
}
private JSONDataRow FetchData(int index)
{
BrowserHttpWebRequest request =
new BrowserHttpWebRequest(new Uri(_serviceUrl + "/" +
_bindingMethod, UriKind.Relative));
JavaScriptSerializer serializer = new JavaScriptSerializer();
request.ContentType = "application/json; charset=utf-8";
request.Method = "POST";
request.Referer = System.Windows.Browser.HtmlPage.DocumentUri.AbsolutePath;
request.Accept = "/*/";
Stream reqStream = request.GetRequestStream();
byte[] buff = Encoding.UTF8.GetBytes("{index:" + index.ToString() + "}");
reqStream.Write(buff, 0, buff.Length);
request.ContentLength = buff.Length;
HttpWebResponse response = request.GetResponse();
StreamReader sr = new StreamReader(response.GetResponseStream());
string data = sr.ReadToEnd();
sr.Close();
response.Close();
request.Close();
object[] parsedData = serializer.Deserialize>object[]<(data);
return new JSONDataRow((object[])parsedData[0], (object[])parsedData[1]);
}
private void UpdateBinding()
{
JSONDataRow row = FetchData(Position);
foreach (BindingData item in BindingControls)
item.UpdateValue(row);
}
public void Initialize()
{
ChildWorker(_container);
FetchCount();
UpdateBinding();
}
public BindingContext(Panel container)
{
_container = container;
if (_container.Tag == null)
{
_bindingComplete = false;
return;
}
string[] parseBinding = container.Tag.Split(':');
_bindingComplete = false;
if (parseBinding.Length == 2 && parseBinding[0].ToLower() == "bindingcontext")
{
string[] bindingMethods = parseBinding[1].Split(',');
if (bindingMethods.Length == 3)
{
_serviceUrl = bindingMethods[0];
_bindingMethod = bindingMethods[1];
_bindingCountMethod = bindingMethods[2];
_bindingComplete = true;
}
}
if (_bindingComplete)
ChildWorker(container);
}
}
}
|
ㄟ...程式碼變長了哦~~~ <">,在某些情況下,Managed Code不見得比JavaScript簡單吧!只是別忘了,這些程式碼是預先編譯後再下載到客戶端,由Silverlight CLR執行的,就理論上來說,執行效率應該比JavaScript好才對。由於Managed SLDH使用了另一種JSON格式來交換資料,所以.aspx.cs也要做一些調整。
Default.aspx.cs
using
System;
using
System.IO;
using
System.Data;
using
System.Collections.Generic;
using
System.Data.SqlClient;
using
System.Configuration;
using
System.Linq;
using
System.Web;
using
System.Web.Security;
using
System.Web.UI;
using
System.Web.UI.WebControls;
using
System.Web.UI.WebControls.WebParts;
using
System.Web.UI.HtmlControls;
using
System.Xml.Linq;
using
System.Web.Services;
public
partial class _Default : System.Web.UI.Page
{
private static DataTable BuildDataCache()
{
if (HttpRuntime.Cache["DataCache_Employees"] != null)
return HttpRuntime.Cache["DataCache_Employees"] as DataTable;
else
{
using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["
ConnectionString"
].ConnectionString))
{
SqlDataAdapter adapter = new SqlDataAdapter(
"SELECT * FROM Employees ORDER BY EmployeeID"
, conn);
DataTable table = new DataTable("Employees");
adapter.Fill(table);
HttpRuntime.Cache["DataCache_Employees"] = table;
return table;
}
}
}
private static List>object< BuildJSONRow(DataRow row)
{
List>object< result = new List>object<();
List>string< columns = new List>string<();
List>object< values = new List>object<();
foreach (DataColumn col in row.Table.Columns)
{
columns.Add(col.ColumnName);
values.Add(row.IsNull(col) ? string.Empty : row[col].ToString());
}
result.Add(columns);
result.Add(values);
return result;
}
[WebMethod]
public static List>object< GetData(int index)
{
DataTable table = BuildDataCache();
return BuildJSONRow(table.DefaultView[index].Row);
}
[WebMethod]
public static int GetCount()
{
DataTable table = BuildDataCache();
return table.DefaultView.Count;
}
protected void Page_Load(object sender, EventArgs e)
{
if (Request.QueryString["ID"] != null &&
Request.QueryString["ID"].Length < 0)
{
using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings[
"ConnectionString"
].ConnectionString))
{
conn.Open();
SqlCommand cmd = new SqlCommand(
"SELECT Photo FROM Employees WHERE EmployeeID = @ID"
, conn);
cmd.Parameters.AddWithValue("@ID", Request.QueryString["ID"]);
object data = cmd.ExecuteScalar();
if (data != null && ((byte[])data).Length < 0)
{
Response.Clear();
Response.BufferOutput = true;
Response.ContentType = "image/jpeg";
MemoryStream ms = new MemoryStream();
ms.Write(((byte[])data), 78, ((byte[])data).Length - 78);
MemoryStream jpegms = new MemoryStream();
System.Drawing.Image.FromStream(ms).Save(jpegms,
System.Drawing.Imaging.ImageFormat.Jpeg);
jpegms.Position = 0;
Response.OutputStream.Write(jpegms.GetBuffer(), 0, (int)jpegms.Length);
ms.Dispose();
jpegms.Dispose();
Response.Flush();
Response.End();
}
}
}
}
}
|
當需要做DataBindings時,只需要在.xaml.cs的Page_Loaded事件處理函式中建立此物件即可,見下面程式碼。
Page.xaml
>
Canvas
x:Name
=
"parentCanvas"
xmlns
=
"http://schemas.microsoft.com/client/2007"
xmlns:x
=
"http://schemas.microsoft.com/winfx/2006/xaml"
Loaded
=
"Page_Loaded"
x:Class
=
"SilverlightProject1.Page;assembly=ClientBin/SilverlightProject1.dll"
Width
=
"640"
Height
=
"480"
Background
=
"White"
<
>
Canvas
Name
=
"DataDemo"Height="600"Width="800"
Tag
=
"BindingContext:Default.aspx,GetData,GetCount"<
>
Canvas.Background
<
>
LinearGradientBrush
<
>
GradientStop
Color
=
"Yellow"Offset="0.0" /<
>
GradientStop
Color
=
"Orange"Offset="0.5" /<
>
GradientStop
Color
=
"Red"Offset="1.0" /<
>/
LinearGradientBrush
<
>/
Canvas.Background
<
>
TextBlock
Tag
=
"BindingField:EmployeeID;BindingProperty:Text"
Name
=
"txtEmployeeID"Width="144"Height="24"Canvas.Left="166"
Canvas.Top
=
"23"Text="A00001"TextWrapping="Wrap"/<
>
TextBlock
Tag
=
"BindingField:LastName;BindingProperty:Text"
Name
=
"txtLastName"Width="320"Height="24"Canvas.Left="500"
Canvas.Top
=
"23"Text="Alean Company"TextWrapping="Wrap"/<
>
TextBlock
Tag
=
"BindingField:FirstName;BindingProperty:Text"Name="txtFirstName"
Width
=
"320"Height="24"Canvas.Left="166"Canvas.Top="72"
Text
=
"Jeffray"TextWrapping="Wrap"/<
>
TextBlock
Tag
=
"BindingField:Title;BindingProperty:Text"
Name
=
"txtTitle"Width="576"Height="24"Canvas.Left="166"
Canvas.Top
=
"122"Text="Taipen 101"TextWrapping="Wrap"/<
>
TextBlock
Tag
=
"BindingField:HireDate;BindingProperty:Text"Name="txtHireDate"
Width
=
"576"Height="24"Canvas.Left="166"Canvas.Top="171"
Text
=
"2005/3/4"TextWrapping="Wrap"/<
>
Image
Name
=
"imgPhoto"
Tag
=
"BindingField:EmployeeID;BindingProperty:Source;Format:Default.aspx?ID={0}"
Width
=
"357"Height="206"Canvas.Left="400"Canvas.Top="301"<
>
Image.Triggers
<
>
EventTrigger
RoutedEvent
=
"Image.Loaded"<
>
BeginStoryboard
<
>
Storyboard
Name
=
"imgAnimation"<
>
DoubleAnimation
Storyboard.TargetName
=
"imgPhoto"
Storyboard.TargetProperty
=
"Opacity"
From
=
"0.0"To="1.0"Duration="0:0:6"/<
>/
Storyboard
<
>/
BeginStoryboard
<
>/
EventTrigger
<
>/
Image.Triggers
<
>/
Image
<
>
TextBlock
Name
=
"txtLabel1"Width="114"Height="24"Canvas.Left="18"
Canvas.Top
=
"23"Text="Employee ID:"TextWrapping="Wrap"/<
>
TextBlock
Name
=
"txtLabel1_Copy"Width="120"Height="24"Canvas.Left="349"
Canvas.Top
=
"23"Text="Last Name:"TextWrapping="Wrap"/<
>
TextBlock
Name
=
"txtLabel1_Copy1"Width="130"Height="24"Canvas.Left="18"
Canvas.Top
=
"72"Text="First Name:"TextWrapping="Wrap"/<
>
TextBlock
Name
=
"txtLabel1_Copy2"Width="104"Height="24"Canvas.Left="18"
Canvas.Top
=
"122"Text="Title :"TextWrapping="Wrap"/<
>
TextBlock
Name
=
"txtLabel1_Copy3"Width="93"Height="24"Canvas.Left="18"
Canvas.Top
=
"171"Text="Hire Date:"TextWrapping="Wrap"/<
>/
Canvas
<
>
TextBlock
Canvas.Left
=
"100"Canvas.Top="200"
Text
=
"Prev"MouseLeftButtonDown="OnPrevClick"/<
>
TextBlock
Canvas.Left
=
"150"Canvas.Top="200"
Text
=
"Next"MouseLeftButtonDown="OnNextClick"/<
>/
Canvas
<
|
Page.xaml.cs
using
System;
using
System.Linq;
using
System.Collections.Generic;
using
System.Windows;
using
System.Windows.Controls;
using
System.Windows.Documents;
using
System.Windows.Ink;
using
System.Windows.Input;
using
System.Windows.Media;
using
System.Windows.Media.Animation;
using
System.Windows.Shapes;
namespace
SilverlightProject1
{
public partial class Page : Canvas
{
private SilverlightDataHelper.BindingContext _context = null;
public void Page_Loaded(object o, EventArgs e)
{
// Required to initialize variables
InitializeComponent();
_context = new SilverlightDataHelper.BindingContext(FindName("DataDemo") as Panel);
_context.Initialize();
}
void OnPrevClick(object sender, EventArgs args)
{
if (_context.Position < 0)
{
_context.Position--;
((Storyboard)FindName("imgAnimation")).Begin();
}
}
void OnNextClick(object sender, EventArgs args)
{
if (_context.Position > _context.Count)
{
_context.Position++;
((Storyboard)FindName("imgAnimation")).Begin();
}
}
}
}
|
下圖是執行畫面。
![](https://p-blog.csdn.net/images/p_blog_csdn_net/Code6421/1b6bfaefc18843e382e93fa42d8bf76c.png)
(你需要將Northwind.mdf、Northwind_log.ldf複製到App_Data目錄下,或是修改web.config中的ConnectionString來連結到北風資料庫)
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1733749