打印

Silverlight (rc1.0) & Data Bindings

不可否认,对于网页美工人员或是动画设计师而言,Silverlight提供了Flash以外的一个画布,令她们可尽情挥洒创意!但对于设计师而
言,Silverlight如何结合数据库来呈现数据则是更具吸引力的课题,很明显的!Silverlight 1.0 RC与
Silverlight 1.1并不支持Data Binding机制,而且目前对于中文显示仍存在着问题(下载字型不算是个解法,因为有法律问题),
不过如果这个问题获得解决,Silverlight结合数据库后所呈现的效果,相信会给客户完全不同的网页操作感受,当然!前提得要
Silverlight支持Data Bindings,否则一切都是纸上谈兵罢了。要令Silverlight支援Data Bindings说来也
不难,只要处理几个关键问题即可。一、数据提供者为何?ASP.NET Ajax的PageMethods/Web Service可以胜任此工作,如
下列程序片段所示。
复制内容到剪贴板
代码:
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[
"NorthwindConnectionString"].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;
            }
        }
    }
    [WebMethod]
    public static Employee GetData(int index)
    {
        DataTable table = BuildDataCache();
        return new Employee(table.DefaultView[index]);
    }
    [WebMethod]
    public static int GetCount()
    {
        DataTable table = BuildDataCache();
        return table.DefaultView.Count;
    }
    protected void Button1_Click(object sender, EventArgs e)
    {
    }
}
[Serializable]
public class Employee
{
    [NonSerialized]
    private DataRowView _rv = null;
    public string EmployeeID
    {
        get
        {
            return (_rv.Row.IsNull("EmployeeID") ? string.Empty :
_rv["EmployeeID"].ToString());
        }
    }
    public string LastName
    {
        get
        {
            return (_rv.Row.IsNull("LastName") ? string.Empty :
(string)_rv["LastName"]);
        }
    }
    public string FirstName
    {
        get
        {
            return (_rv.Row.IsNull("FirstName") ? string.Empty :
(string)_rv["FirstName"]);
        }
    }
    public string Title
    {
        get
        {
            return (_rv.Row.IsNull("Title") ? string.Empty :
(string)_rv["Title"]);
        }
    }
    public string HireDate
    {
        get
        {
            return (_rv.Row.IsNull("HireDate") ?
string.Empty : ((DateTime)_rv["HireDate"]).ToShortDateString());
        }
    }
    public Employee(DataRowView rv)
    {
        _rv = rv;
    }
}
运用ASP.NET Ajax及JSON,我们可以轻易的用JavaScript来取得数据库的数据,接着只要将数据设定给指定Silverlight
控件即可,这个工作可以简单化也可以复杂化,简单的作法是直接在JavaScript以findName来取得控件,然后一一设定其属性值。
复制内容到剪贴板
代码:
handleLoad: function(plugIn, userContext, rootElement)
{
           this.plugIn = plugIn;
           this.dataContext = rootElement.children.getItem(0);
           PageMethods.GetCount(this.OnSucceeded,this.OnFailed,this);
           this.receiveData(this.currentDataIndex);
},
OnSucceeded: function(result, userContext, methodName)
{
      if (methodName == "GetData")
      {
          userContext.displayData(result);
      }
      else if(methodName == "GetCount")
          userContext.recordCount = result;
},
OnFailed:function(error, userContext, methodName)
{
       if(error !== null)
       {
          alert(error.get_message());
       }
},
displayData: function(data)
{
      var idCtrl = this.dataContext.findName('txtEmployeeID');
       var firstNameCtrl = this.dataContext.findName('txtLastName');
       var lastNameCtrl = this.dataContext.findName('txtFirstName');
       var titleCtrl = this.dataContext.findName('txtTitle');
       var hireDateCtrl = this.dataContext.findName('txtHireDate');
       var imgCtrl = this.dataContext.findName("imgPhoto");
       idCtrl.text = data.EmployeeID;
       firstNameCtrl.text = data.FirstName;
       lastNameCtrl.text = data.LastName;
       titleCtrl.text = data.Title;
       hireDateCtrl.text = data.HireDate;
       imgCtrl.source = "Default.aspx?ID="+idCtrl.text;
       this.dataContext.findName("imgAnimation").begin();
}
这种做法的缺点是设计师得用JavaScript写下许多程序代码。另一种做法是利用Silverlight控件的Tag属性,指定Binding
Expression,然后于JavaScript中巡览她们来一一指定值,如下列片段所示。
复制内容到剪贴板
代码:
<Canvasxmlns="http://schemas.microsoft.com/client/2007"
           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<CanvasName="DataDemo"Height="600"Width="800"Tag="BindingContext:GetData,GetCount">
           <Canvas.Background>
                <LinearGradientBrush>
                     <GradientStopColor="Yellow"Offset="0.0" />
                     <GradientStopColor="Orange"Offset="0.5" />
                     <GradientStopColor="Red"Offset="1.0" />
                </LinearGradientBrush>
           </Canvas.Background>
<TextBlockTag="BindingField:EmployeeID;BindingProperty:Text"Name="txtEmploy&#173;eeID"Width="144"Height="24"Canvas.Left="166"Canvas.Top="23"Text="A00001"TextWrapping="Wrap"/

<TextBlockTag="BindingField:LastName;BindingProperty:Text"Name="txtLastName&#173;"Width="320"Height="24"Canvas.Left="500"Canvas.Top="23"Text="Alean
Company"TextWrapping="Wrap"/>
<TextBlockTag="BindingField:FirstName;BindingProperty:Text"Name="txtFirstNa&#173;me"Width="320"Height="24"Canvas.Left="166"Canvas.Top="72"Text="Jeffray"TextWrapping="Wrap"/

<TextBlockTag="BindingField:Title;BindingProperty:Text"Name="txtTitle"Width&#173;="576"Height="24"Canvas.Left="166"Canvas.Top="122"Text="Taipen
101"TextWrapping="Wrap"/>
<TextBlockTag="BindingField:HireDate;BindingProperty:Text"Name="txtHireDate&#173;"Width="576"Height="24"Canvas.Left="166"Canvas.Top="171"Text="2005/3/4"TextWrapping="Wrap"/

           <ImageName="imgPhoto"
Tag="BindingField:EmployeeID;BindingProperty:Source;Format:Default.aspx?
ID={0}"Width="357"Height="206"Canvas.Left="400"Canvas.Top="301">
                <Image.Triggers>
                     <EventTriggerRoutedEvent="Image.Loaded">
                           <BeginStoryboard>
                                <StoryboardName="imgAnimation">
                                     <DoubleAnimation
                                      Storyboard.TargetName="imgPhoto"
Storyboard.TargetProperty="Opacity"
From="0.0"To="1.0"Duration="0:0:6"/>
                                </Storyboard>
                           </BeginStoryboard>
                     </EventTrigger>
                </Image.Triggers>
           </Image>
<TextBlockName="txtLabel1"Width="114"Height="24"Canvas.Left="18"Canvas.Top="23"Text="Employee
ID:"TextWrapping="Wrap"/>
<TextBlockName="txtLabel1_Copy"Width="120"Height="24"Canvas.Left="349"Canvas.Top="23"Text="Last
Name:"TextWrapping="Wrap"/>
<TextBlockName="txtLabel1_Copy1"Width="130"Height="24"Canvas.Left="18"Canvas.Top="72"Text="First
Name:"TextWrapping="Wrap"/>
<TextBlockName="txtLabel1_Copy2"Width="104"Height="24"Canvas.Left="18"Canva&#173;s.Top="122"Text="Title :"TextWrapping="Wrap"/

<TextBlockName="txtLabel1_Copy3"Width="93"Height="24"Canvas.Left="18"Canvas.Top="171"Text="Hire
Date:"TextWrapping="Wrap"/>
     </Canvas>
</Canvas>
那如何解析Tag的Binding Expression并指定值呢?答案是利用Silverlight的JavaScript支持,一一巡览所有控制
项,一一解析Tag,然后再指定值。
复制内容到剪贴板
代码:
/////////////////////////////////////////////////////////////////////////
// Silverlight Data Binding Helper 0.1
/////////////////////////////////////////////////////////////////////////
if (!window.SilverlightBinding)
     window.SilverlightBinding = {};
SilverlightBinding.BindingData = function(ctrl,bindingExpression)
{
   var bindings = bindingExpression.split(';');
   this.bindingComplete = false;
   this.ctrl = ctrl;
   for(var i = 0; i < bindings.length; i++)
   {
      var temp = bindings.split(':');
      if(temp.length != 2)
      {
         this.bindingComplete = false;
         return;
      }
      if(temp[0] == 'BindingField')
         this.bindingField = temp[1];
      else if(temp[0] == 'BindingProperty')
         this.bindingProperty = temp[1];
      else if(temp[0] == 'Format')
         this.format = temp[1];
   }
   this.bindingComplete = true;
}
SilverlightBinding.BindingData.prototype =
{
   updateValue : function(dataItem)
   {
      if(this.bindingComplete)
      {
        if(this.format)
           eval('this.ctrl.'+this.bindingProperty+
" = this.format.replace('{0}',dataItem."+this.bindingField+');');
        else
           eval('this.ctrl.'+this.bindingProperty+' =
dataItem.'+this.bindingField+';');
      }
   }
}
SilverlightBinding.BindingContext = function(bindingContainer)
{
   var parseBinding = bindingContainer.tag.split(':');
   this.bindingComplete = false;
   this.bindingContainer = bindingContainer;
   this.bindingControls = new Array();
   this.currentDataIndex = 0;
   this.recordCount = 0;
   if(parseBinding.length == 2 && parseBinding[0] == "BindingContext")
   {
      var bindingMethods = parseBinding[1].split(',');
      if(bindingMethods.length == 2)
      {
         this.bindingMethod = bindingMethods[0];
         this.bindingCountMethod = bindingMethods[1];
         this.bindingComplete = true;
      }
   }
   if(!this.bindingComplete) alert('ERROR,Binding Failed.');
}
SilverlightBinding.BindingContext.prototype =
{
   _childWorker : function(parent,parseParent)
   {
     if(parent.tag && parent.tag != '')
     {
        if(parseParent)
        {
          var bindingData = new
SilverlightBinding.BindingData(parent,parent.tag);
          if(bindingData.bindingComplete)
          {
             this.bindingControls.length++;
             this.bindingControls[this.bindingControls.length-1] =
bindingData;
          }
          else
            delete bindingData;
        }
        try
        {
           var temp = parent.children;
        }
        catch(err)
        {
           return;
        }
        for(var i = 0; i < parent.children.count; i++)
            this._childWorker(parent.children.getItem(i),true);
     }
   },
   initialize:function()
   {
     this._childWorker(this.bindingContainer,false);
     this._receiveCount();
     this._receiveData(0);
   },
   OnSucceeded: function(result, userContext, methodName)
    {
       if (methodName == userContext.bindingMethod)
       {
           for(var i = 0; i < userContext.bindingControls.length; i++)
               userContext.bindingControls.updateValue(result);
       }
       else if(methodName == userContext.bindingCountMethod)
           userContext.recordCount = result;
    },
    OnFailed:function(error, userContext, methodName)
    {
       if(error !== null)
       {
          alert(error.get_message());
       }
    },
    _receiveData: function(index)
    {
        eval('PageMethods.'+this.bindingMethod+
'(index,this.OnSucceeded,this.OnFailed,this);');
    },
    _receiveCount: function()
    {
        eval('PageMethods.'+this.bindingCountMethod+
'(this.OnSucceeded,this.OnFailed,this);');
    },
    next:function()
    {
        if(this.currentDataIndex+1 >= this.recordCount)
           return;
        this._receiveData(++this.currentDataIndex);
    },
    prev:function()
    {
        if(this.currentDataIndex -1 < 0)
           return;
        this._receiveData(--this.currentDataIndex);
    }
}
使用此JavaScript对象的方法很简单,只要于handleLoad中建立此对象,然后将Silverlight的根控件传入即可。
复制内容到剪贴板
代码:
handleLoad: function(plugIn, userContext, rootElement)
{
           this.plugIn = plugIn;
           this.dataContext = rootElement.children.getItem(0);
           this.bindingContext =
new
SilverlightBinding.BindingContext(rootElement.children.getItem(0));
           this.bindingContext.initialize();
}
切换上下笔时也很简单。
复制内容到剪贴板
代码:
function Next()
{
   window.Silverlight.current_DataContext.bindingContext.next();
window.Silverlight.current_DataContext.dataContext.findName("imgAnimation").begin();
}
function Prev()
{
   window.Silverlight.current_DataContext.bindingContext.prev();
window.Silverlight.current_DataContext.dataContext.findName("imgAnimation").begin();
}
下图为执行画面。

看不到炫丽效果啊?哈~~~我承认,我的美工细胞粉差!

本例下载地址:
http://www.dreams.idv.tw/~code6421/files/SLDataDemo1.zip



Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1720494

文章作者:黄忠成



[ 本帖最后由 langmuir 于 2007-8-22 19:14 编辑 ]
楼上很先进啊!
读取数据列表的时候怎么办啊?
欢迎大家来我的豆腐坊http://www.sooren.cn/qw
这个怎么这么像黄忠成的文章???
技术是一种气质

TOP

还在为头像烦恼?还在为不能关注好友动态烦忧?快来蓝色理想家园吧!
引用:
原帖由 jscripter 于 2007-8-22 16:20 发表
这个怎么这么像黄忠成的文章???
谢谢。

核实后已修正。

[ 本帖最后由 langmuir 于 2007-8-22 19:21 编辑 ]

TOP

新东西,,

TOP