Silverlight 的 DataBindings

 
Silverlight Data Bindings Silverlight ASP.NET Ajax
 
 
文/黃忠成
 不可否認,對於網頁美工人員或是動畫設計師而言,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,methodName)
{
      if (methodName == "GetData")
      {
          userContext.displayData(result);
      }
      else if(methodName == "GetCount")
          userContext.recordCount = result;
},         
OnFailed:function(error,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 中巡覽她們來一一指定值,如下列片段所示。
< Canvas xmlns = "http://schemas.microsoft.com/client/2007"
           xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml">
     < Canvas Name = "DataDemo"Height="600"Width="800"Tag="BindingContext: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>
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[i].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,methodName)
    {
       if (methodName == userContext.bindingMethod)
       {             
           for(var i = 0; i < userContext.bindingControls.length; i++)
               userContext.bindingControls[i].updateValue(result);
       }
       else if(methodName == userContext.bindingCountMethod)
           userContext.recordCount = result;
    },         
    OnFailed:function(error,methodName)
    {
       if(error !== null)
       {
          alert(error.get_message());
       }
    },
    _receiveData: function(index)
    {
        eval('PageMethods.'+this.bindingMethod+
'(index,this.OnSucceeded,this);' );
    },
    _receiveCount: function()
    {
        eval('PageMethods.'+this.bindingCountMethod+
'(this.OnSucceeded,
    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,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
 

相关文章

如何在Silverlight4(XAML)中绑定IsEnabled属性?我试过简单的...
我正在编写我的第一个vb.net应用程序(但我也会在这里标记c#,...
ProcessFile()是在UIThread上运行还是在单独的线程上运行.如...
我从同行那里听说,对sharepoint的了解对职业生涯有益.我们不...
我正在尝试保存一个类我的类对象的集合.我收到一个错误说明:...
我需要根据Silverlight中的某些配置值设置给定控件的Style.我...