Silverlight数据绑定/IValueConverter学习笔记

先回忆一下aspx中的处理:

在aspx中,可以直接在后台定义一个变量,然后前台就可以用<%=xxx%>来将其"绑定"html控件上,比如下面这样,实在是很方便:

ExpandedBlockStart.gif 代码
using  System;

namespace  WebApplication1
{
    
public   partial   class  _Default : System.Web.UI.Page
    {
        
protected   string  _Test  =  DateTime.Now.ToString();

        
protected   void  Page_Load( object  sender, EventArgs e)
        {

        }
    }
}

 

ExpandedBlockStart.gif 代码
<% @ Page Language = " C# "  AutoEventWireup = " true "  CodeBehind = " Default.aspx.cs "  Inherits = " WebApplication1._Default "   %>

<! DOCTYPE html PUBLIC  " -//W3C//DTD XHTML 1.0 Transitional//EN "   " http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd " >

< html xmlns = " http://www.w3.org/1999/xhtml "   >
< head runat = " server " >
    
< title ></ title >
</ head >
< body >
    
< form id = " form1 "  runat = " server " >
    
< input id = " Text1 "  type = " text "   value = " <%=_Test %> " />
    
</ form >
</ body >
</ html >

 

但到了Silverlight中,要想直接将后台的变量绑定到某个控件上却是行不通的,通常我们得先定义一个类,然后在类里定义属性,才能把类实例的属性绑定到控件:

简单绑定: 

ExpandedBlockStart.gif 代码
using  System;
using  System.Windows;
using  System.Windows.Controls;
using  System.Windows.Data;
using  System.Windows.Shapes;

namespace  BindVariable
{
    
public   partial   class  MainPage : UserControl
    {

        
public   class  MyClass {  public   string  Test {  set get ; } }       

        
public  MyClass TestClass;
     
        
public  MainPage()
        {           
            InitializeComponent();           
            TestClass 
=   new  MyClass();
            TestClass.Test 
=   " 123 " ;
            
this .textBox1.DataContext  =  TestClass;           
        }
      
    }   
}

 

     < StackPanel >         
      
< TextBox  x:Name ="textBox1"   Text =" {Binding Test} " />   
    
</ StackPanel >

 

这样就完成了功能最简单的绑定,还想玩得更深入一点,比如实现OneWay,TwoWay方式的绑定(不清楚绑定模式的朋友,建议先参看http://www.cnblogs.com/yjmyzz/archive/2009/11/09/1599058.html),这样仍然不行,比如我们稍微把刚才的代码改一下:

"自动更新"的绑定: 

ExpandedBlockStart.gif 代码
< UserControl
    
xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d
="http://schemas.microsoft.com/expression/blend/2008"  xmlns:mc ="http://schemas.openxmlformats.org/markup-compatibility/2006"
    x:Class
="BindVariable.MainPage"
   
>    
    
    
< StackPanel  Orientation ="Vertical" >         
      
< TextBox  x:Name ="textBox1"  Text =" {Binding Test} " />   
      
< Button  x:Name ="btnChange"  Content ="Change Test"  Click ="btnChange_Click" ></ Button >
    
</ StackPanel >
</ UserControl >

 

ExpandedBlockStart.gif 代码
using  System;
using  System.Windows;
using  System.Windows.Controls;
using  System.Windows.Data;
using  System.Windows.Shapes;

namespace  BindVariable
{
    
public   partial   class  MainPage : UserControl
    {

        
public   class  MyClass {  public   string  Test {  set get ; } }       

        
public  MyClass TestClass;
     
        
public  MainPage()
        {           
            InitializeComponent();           
            TestClass 
=   new  MyClass();
            TestClass.Test 
=   " 123 " ;
            
this .textBox1.DataContext  =  TestClass;          
        }

    
private   void  btnChange_Click( object  sender, RoutedEventArgs e)
        {
            
this .TestClass.Test  =   " 456 " ;
        }
      
    }   
}

运行后,点击按钮,发现textbox1中的内容并无变化,原因是:要想实现源与目标的数据自动关联更新,MyClass得实现INotifyPropertyChanged接口,我们把MyClass的定义改成下面这样: 

ExpandedBlockStart.gif 代码
public   class  MyClass:INotifyPropertyChanged {
    
public   event  PropertyChangedEventHandler PropertyChanged;

    
private   string  _test;

    
public   string  Test 
    { 
        
set {
        _test 
=  value;
        
if  (PropertyChanged  !=   null
        {
            PropertyChanged(
this new  PropertyChangedEventArgs( " Test " ));
        }
    }
        
get  {  return  _test; }
    } 
}

再次运行,发现点击按钮后,textbox1的内容变成了456,达到预期的效果了.
绑定集合(数据集):

很多应用场合中,数据来源不仅只有一个实例(或一条记录)--比如从数据库中检索的记录,这时如果想绑定数据并实现自动更新,应使用集合绑定(类似于aspx中的DataSet或DataTable)。要注意的是,使用集合绑定并实现自动更新,除了要实现 INotifyPropertyChanged 外,还要实现 INotifyCollectionChanged。幸好.net框架已经有一个ObservableCollection<T> 类,该类具有 INotifyCollectionChanged 和 INotifyPropertyChanged 的内置实现。可以直接拿来用:

ExpandedBlockStart.gif 代码
< UserControl
    
xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d
="http://schemas.microsoft.com/expression/blend/2008"  xmlns:mc ="http://schemas.openxmlformats.org/markup-compatibility/2006"
    x:Class
="BindVariable.MainPage"
    xmlns:local
="clr-namespace:BindVariable"
   
>
    
< StackPanel  Orientation ="Vertical" >        
        
< ListBox  x:Name ="lst"   >
            
< ListBox.ItemTemplate >
                
< DataTemplate >
                    
< StackPanel >
                        
< TextBlock  Text =" {Binding Test} " ></ TextBlock >
                    
</ StackPanel >
                
</ DataTemplate >
            
</ ListBox.ItemTemplate >
        
</ ListBox >
        
< Button  x:Name ="btnChange"  Content ="Change Test"  Click ="btnChange_Click" ></ Button >
    
</ StackPanel >
</ UserControl >

 

ExpandedBlockStart.gif 代码
using  System.Collections.ObjectModel;
using  System.Windows;
using  System.Windows.Controls;

namespace  BindVariable
{
    
public   partial   class  MainPage : UserControl
    {

        
public   class  MyClass {  public   string  Test {  set get ; } }        

        ObservableCollection
< MyClass >  oc  =   new  ObservableCollection < MyClass > (){
            
new  MyClass() { Test  =   " 1 "  },
            
new  MyClass() { Test  =   " 2 "  },
            
new  MyClass() { Test  =   " 3 "  }
        };
     
        
public  MainPage()
        {           
            InitializeComponent();
            
this .lst.ItemsSource  =  oc;
        }

        
private   void  btnChange_Click( object  sender, RoutedEventArgs e)
        {
            oc.Add(
new  MyClass() { Test  =   " 4 "  });
        }      
    }
}

IValueConverter:

上述的绑定,都是将数据原封不动的绑定并显示,如果我们希望在绑定时,能对数据的输出做一些变化,比如:代表性别的"1,0"输出时希望变成"男,女",该怎么办呢?(silverlight中可不允许象aspx那样用<%# Eval("Sex").ToString()=="1"?"男":"女"%>来搞定)  答案:IValueConverter 

ExpandedBlockStart.gif 代码
using  System;
using  System.Collections.ObjectModel;
using  System.Windows;
using  System.Windows.Controls;
using  System.Windows.Data;

namespace  BindVariable
{
    
public   partial   class  MainPage : UserControl
    {

        
public   class  MyClass
        {
            
public   string  Test {  set get ; }
            
public   bool  Sex {  set get ; }
        }

        ObservableCollection
< MyClass >  oc  =   new  ObservableCollection < MyClass > (){
            
new  MyClass() { Test  =   " 1 " ,Sex = true  },
            
new  MyClass() { Test  =   " 2 " ,Sex = false  },
            
new  MyClass() { Test  =   " 3 " ,Sex = true  }
        };

        
public  MainPage()
        {
            InitializeComponent();
            
this .lst.ItemsSource  =  oc;
        }

        
private   void  btnChange_Click( object  sender, RoutedEventArgs e)
        {
            oc.Add(
new  MyClass() { Test  =   " 4 " , Sex  =   false  });
        }

    }

    
///   <summary>
    
///  bool转化为性别字符串
    
///   </summary>
     public   class  BoolToSexConverter : IValueConverter
    {

        
public   object  Convert( object  value, Type targetType,  object  parameter, System.Globalization.CultureInfo culture)
        {
            
try
            {
                
return  (( bool )value)  ?   " "  :  " " ;
            }
            
catch
            {
                
return   " ? " ;
            }

        }


        
// 只有TwoWay模式下,才需要实现该方法,否则可以不用理
         public   object  ConvertBack( object  value, Type targetType,  object  parameter, System.Globalization.CultureInfo culture)
        {
            
throw   new  NotImplementedException();
        }
    }
}

 

ExpandedBlockStart.gif 代码
< UserControl
    
xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d
="http://schemas.microsoft.com/expression/blend/2008"  xmlns:mc ="http://schemas.openxmlformats.org/markup-compatibility/2006"
    x:Class
="BindVariable.MainPage"
    xmlns:local
="clr-namespace:BindVariable"
   
>
    
< StackPanel  Orientation ="Vertical" >   
        
< StackPanel.Resources >
            
< local:BoolToSexConverter  x:Key ="Bool2Sex" ></ local:BoolToSexConverter >
        
</ StackPanel.Resources >
        
< ListBox  x:Name ="lst"   >
            
< ListBox.ItemTemplate >
                
< DataTemplate >
                    
< StackPanel  Orientation ="Horizontal" >
                        
< TextBlock  Text =" {Binding Test} " ></ TextBlock >
                        
< TextBlock  Text ="," ></ TextBlock >
                        
< TextBlock  Text =" {Binding Path=Sex,  Converter={StaticResource Bool2Sex}} " ></ TextBlock >
                    
</ StackPanel >
                
</ DataTemplate >
            
</ ListBox.ItemTemplate >
        
</ ListBox >
        
< Button  x:Name ="btnChange"  Content ="Change Test"  Click ="btnChange_Click" ></ Button >
    
</ StackPanel >
</ UserControl >

也许您注意到了IValueConverter的Convert方法中,还能传入参数!我们可以利用这个玩点小花样,比如界面上有三个矩形,其中"矩形2的宽度"等于"矩形1的宽度"+"一个任意指定的固定值",矩形3的宽度矩形1与矩形2的宽度总和,不允用 rect2.width = rect1.width,rect3.width = rect2.width + rect1.width 来处理:) 您会怎么做呢? 

ExpandedBlockStart.gif 代码
using  System;
using  System.Windows;
using  System.Windows.Controls;
using  System.Windows.Data;

namespace  BindVariable
{
    
public   partial   class  MainPage : UserControl
    {       
        
public  MainPage()
        {
            InitializeComponent();            
        }
    }

    
public   class  DoubleAddConverter : IValueConverter
    {

        
public   object  Convert( object  value, Type targetType,  object  parameter, System.Globalization.CultureInfo culture)
        {
            
try
            {
                
return   double .Parse(value.ToString())  +   double .Parse(parameter.ToString());
            }
            
catch
            {
                
return   50.0 ;
            }

        }


        
// 只有TwoWay模式下,才需要实现该方法,否则可以不用理
         public   object  ConvertBack( object  value, Type targetType,  object  parameter, System.Globalization.CultureInfo culture)
        {
            
throw   new  NotImplementedException();
        }
    }


    
public   class  FrameworkElementAddConverter : IValueConverter
    {

        
public   object  Convert( object  value, Type targetType,  object  parameter, System.Globalization.CultureInfo culture)
        {
            
try
            {
                
return   double .Parse(value.ToString())  +  ((App.Current.RootVisual  as  FrameworkElement).FindName(parameter.ToString())  as  FrameworkElement).Width;
            }
            
catch
            {
                
return   50.0 ;
            }

        }


        
// 只有TwoWay模式下,才需要实现该方法,否则可以不用理
         public   object  ConvertBack( object  value, Type targetType,  object  parameter, System.Globalization.CultureInfo culture)
        {
            
throw   new  NotImplementedException();
        }
    }
    
}

 

 

ExpandedBlockStart.gif 代码
< UserControl
    
xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d
="http://schemas.microsoft.com/expression/blend/2008"  xmlns:mc ="http://schemas.openxmlformats.org/markup-compatibility/2006"
    x:Class
="BindVariable.MainPage"
    xmlns:local
="clr-namespace:BindVariable"
   
>
    
< StackPanel  Orientation ="Vertical"  HorizontalAlignment ="Left"   >          
        
< StackPanel.Resources >
            
< local:DoubleAddConverter  x:Key ="DoubleAdd" ></ local:DoubleAddConverter >
            
< local:FrameworkElementAddConverter  x:Key ="FEAdd" ></ local:FrameworkElementAddConverter >
        
</ StackPanel.Resources >
        
        
< Rectangle  x:Name ="rect1"  Width ="100"  Height ="50"  Fill ="Gray"  HorizontalAlignment ="Left" ></ Rectangle >
        
        
< Rectangle  x:Name ="rect2"  Height ="50"  Width =" {Binding Width, Converter={StaticResource DoubleAdd}, ConverterParameter=100, ElementName=rect1, Mode=OneWay} "   Fill ="Red"  HorizontalAlignment ="Left" ></ Rectangle >
        
        
< Rectangle  x:Name ="rect3"  Height ="50"   Fill ="Blue"  Width =" {Binding Width, Converter={StaticResource FEAdd}, ConverterParameter=rect2, ElementName=rect1, Mode=OneWay} " ></ Rectangle >
    
</ StackPanel >
</ UserControl >

 

这样就搞定了,也许有人会问:为啥不用  rect2.width = rect1.width,rect3.width = rect2.width + rect1.width 呢?不是更简单吗?

存在即合理,这样的好处是不必用硬编码把逻辑写死,我们可以把常用的转换处理抽象出来,比如封装成一个单纯的dll程序集,以后需要用到的地方,直接引用就可以了,能有效的重用代码。

 

转载请注明来自菩提树下的杨过http://www.cnblogs.com/yjmyzz/archive/2009/12/07/silverlight-binding.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值