仅在数量绑定创造时使用数据源更新目的,仅在数码绑定创制时利用数据源更新目的

3种多少绑定情势  One提姆(Tim)e(五次绑定) OneWay(单项绑定) TwoWay(双向绑定)

3种多少绑定格局  One提姆e(一遍绑定) OneWay(单项绑定) TwoWay(双向绑定)

One提姆(Tim)e:仅在数量绑定创制时利用数据源更新目的。

One提姆e:仅在多少绑定创造时行使数据源更新目的。

列子:

列子:

先是步,创建数据源对象让Person类实现INotifyPropertyChanged接口,该接口具有PropertyChanged事件,PropertyChanged事件在数据源发生变化时候通告绑定

先是步,创设数据源对象让Person类实现INotifyPropertyChanged接口,该接口具有PropertyChanged事件,PropertyChanged事件在数据源暴发变化时候公告绑定

.cs

.cs

namespace SilverlightApplication2
{
    public class Person:INotifyPropertyChanged
    {

        public event PropertyChangedEventHandler PropertyChanged;

        private String _Name;
        public String Name
        {
            get { return this._Name; }
            set
            {
                this._Name = value;
                NotifyPropertyChanged("Name");
            }
        }

        private int _Age;
        public  int Age
        {
            get { return this._Age; }
            set
            {
                this._Age = value;
                NotifyPropertyChanged("Age");

            }
        }

        private String _Address;
        public String Address
        {
            get { return this._Address; }
            set
            {
                this._Address = value;
                NotifyPropertyChanged("Address");
            }
        }

        public void NotifyPropertyChanged(String propertyName)
        {
            if(PropertyChanged!=null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

    }

}
namespace SilverlightApplication2
{
    public class Person:INotifyPropertyChanged
    {

        public event PropertyChangedEventHandler PropertyChanged;

        private String _Name;
        public String Name
        {
            get { return this._Name; }
            set
            {
                this._Name = value;
                NotifyPropertyChanged("Name");
            }
        }

        private int _Age;
        public  int Age
        {
            get { return this._Age; }
            set
            {
                this._Age = value;
                NotifyPropertyChanged("Age");

            }
        }

        private String _Address;
        public String Address
        {
            get { return this._Address; }
            set
            {
                this._Address = value;
                NotifyPropertyChanged("Address");
            }
        }

        public void NotifyPropertyChanged(String propertyName)
        {
            if(PropertyChanged!=null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

    }

}

关于INotifyPropertyChanged
 参见http://www.cnblogs.com/beginor/archive/2012/08/13/2636418.html

关于INotifyPropertyChanged
 参见http://www.cnblogs.com/beginor/archive/2012/08/13/2636418.html

INotifyPropertyChanged

INotifyPropertyChanged

它的效劳:向客户端发出某一属性值已更改的关照。

它的效益:向客户端发出某一属性值已更改的公告。

当属性改变时,它可以布告客户端,并开展界面数据更新.而我辈不要写过多扑朔迷离的代码来更新界面数据,那样可以完成方法简单而清丽,松耦合和让艺术变得更通用.可用的地方太多了:例如上传进度,实时后台数据变动等地点.近期本人意识winform和silverlight都帮忙,确实是一个有力的接口.

当属性改变时,它可以通告客户端,并展开界面数据更新.而我辈毫不写过多繁杂的代码来更新界面数据,这样能够成功方法简单而清晰,松耦合和让艺术变得更通用.可用的地点太多了:例如上传进度,实时后台数据变动等地点.如今自己发觉winform和silverlight都扶助,确实是一个无敌的接口.

在构造函数中先绑定

在构造函数中先绑定

public Class_Name()   

public Class_Name()   

{   

{   

    User user = new User();    

    User user = new User();    

    user.Name = “your name”;    

    user.Name = “your name”;    

    user.Address = “your address”;    

    user.Address = “your address”;    

  

  

    textBox1.Text = user.Name;   

    textBox1.Text = user.Name;   

    textBox2.Text = user.Address;   

    textBox2.Text = user.Address;   

}  

}  

编纂一个简约的业务类

编写一个简短的业务类

 

 

public class User : INotifyPropertyChanged   

public class User : INotifyPropertyChanged   

{   

{   

    public event PropertyChangedEventHandler PropertyChanged;
   

    public event PropertyChangedEventHandler PropertyChanged;
   

  

  

    private string _name;
   

    private string _name;
   

    public string Name
   

    public string Name
   

    {   

    {   

        get { return _name; }   

        get { return _name; }   

        set    

        set    

        {   

        {   

            _name = value;   

            _name = value;   

           if(PropertyChanged != null)   

           if(PropertyChanged != null)   

            {   

            {   

                PropertyChanged(this, new PropertyChangedEventArgs(“Name”));   

                PropertyChanged(this, new PropertyChangedEventArgs(“Name”));   

            }   

            }   

        }   

        }   

    }   

    }   

  

  

    private string _address;   

    private string _address;   

    public string Address
  

    public string Address
  

    {   

    {   

        get { return _address; }   

        get { return _address; }   

        set    

        set    

        {   

        {   

            _address = value;   

            _address = value;   

            if (PropertyChanged != null)   

            if (PropertyChanged != null)   

            {   

            {   

                PropertyChanged(this, new PropertyChangedEventArgs(“Address”));   

                PropertyChanged(this, new PropertyChangedEventArgs(“Address”));   

            }   

            }   

        }   

        }   

    }   

    }   

}  

}  

 

 

 

 

ObservableCollection

ObservableCollection

绑定到聚集

绑定到聚集

数量绑定的数据源对象可以是一个暗含数据的十足对象,也得以是一个对象的集纳。往日,一贯在座谈哪些将目标对象与一个单一对象绑定。Silverlight中的数据绑定还是能将对象对象与聚集对象相绑定,那也是很常用的。比如呈现作品的题材列表、突显一文山会海图片等。

数据绑定的数据源对象足以是一个包含数据的单纯对象,也能够是一个目的的集纳。以前,平昔在座谈哪边将对象对象与一个纯粹对象绑定。Silverlight中的数据绑定仍是可以将目的对象与聚集对象相绑定,这也是很常用的。比如呈现文章的问题列表、显示一多级图片等。

假设要绑定到一个集合类型的数据源对象,绑定目的可以动用ItemsControl,如ListBox或DataGrid等。此外,通过定制ItemsControl的多少模板(DataTemplate),仍是可以够决定集合对象中每一项的显得。

若果要绑定到一个聚集类型的数据源对象,绑定目标可以行使ItemsControl,如ListBox或DataGrid等。此外,通过定制ItemsControl的数额模板(DataTemplate),还足以控制集合对象中每一项的呈现。

 使用ObservableCollection

 使用ObservableCollection

数据源集合对象必须继承IEnumerable接口,为了让对象属性与数据源集合的更新(不但包括元素的改动,还包括元素的扩充和删除)保持同步,数据源集合还必须贯彻INotifyPropertyChanged接口和INotifyCollectionChanged接口。

数据源集合对象必须继续IEnumerable接口,为了让对象属性与数据源集合的换代(不但包括元素的修改,还包括元素的扩张和删除)保持同步,数据源集合还必须兑现INotifyPropertyChanged接口和INotifyCollectionChanged接口。

在Silverlight中创立数据源集合可以利用内建的ObservableCollection类,因为ObservableCollection类既贯彻了INotifyPropertyChanged接口,又实现了INotifyCollectionChanged接口。使用ObservableCollection类不但可以实现Add、Remove、Clear和Insert操作,还足以触发PropertyChanged事件。

在Silverlight中创制数据源集合可以应用内建的ObservableCollection类,因为ObservableCollection类既实现了INotifyPropertyChanged接口,又实现了INotifyCollectionChanged接口。使用ObservableCollection类不但可以兑现Add、Remove、Clear和Insert操作,还是可以够触发PropertyChanged事件。

 

 

关于 谈谈INotifyPropertyChanged
的实现

关于 谈谈INotifyPropertyChanged
的实现

参见http://www.cnblogs.com/beginor/archive/2012/08/13/2636418.html

参见http://www.cnblogs.com/beginor/archive/2012/08/13/2636418.html

INotifyPropertyChanged 接口是 WPF/Silverlight 开发中分外首要的接口,
它结合了 ViewModel 的底子, 数据绑定基本上都亟待以此接口。 所以,
对它的落实也展现煞是首要, 下面接贴出自己通晓的三种实现模式,
希望能起到抛砖引玉的法力。

INotifyPropertyChanged 接口是 WPF/Silverlight 开发中充分重大的接口,
它结合了 ViewModel 的底蕴, 数据绑定基本上都需要那多少个接口。 所以,
对它的兑现也显得非常重大, 上面接贴出自己清楚的三种实现格局,
希望能起到抛砖引玉的功力。

貌似的兑现格局

这是一种再常见可是的实现情势, 代码如下:

1
2
3
4
5
6
7
8
9
10
public class NotifyPropertyChanged : INotifyPropertyChanged {
    
   public event PropertyChangedEventHandler PropertyChanged;
 
   virtual internal protected void OnPropertyChanged(string propertyName) {
      if (this.PropertyChanged != null) {
         this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
      }
   }
}

这种方法叫做一般的落实模式, 因为它实在是太普通不过了,
而且使用起来也令人备感厌烦, 因为必须指定手工指定属性名称:

1
2
3
4
5
6
7
8
9
10
11
12
public class MyViewModel : NotifyPropertyChanged {
 
   private int _myField;
 
   public int MyProperty {
      get { return _myField; }
      set {
         _myField = value;
         OnPropertyChanged("MyProperty");
      }
   }
}

诚如的实现格局

这是一种再平凡可是的贯彻形式, 代码如下:

1
2
3
4
5
6
7
8
9
10
public class NotifyPropertyChanged : INotifyPropertyChanged {
    
   public event PropertyChangedEventHandler PropertyChanged;
 
   virtual internal protected void OnPropertyChanged(string propertyName) {
      if (this.PropertyChanged != null) {
         this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
      }
   }
}

这种方法叫做一般的贯彻格局, 因为它的确是太普通然则了,
而且使用起来也令人深感厌恶, 因为必须指定手工指定属性名称:

1
2
3
4
5
6
7
8
9
10
11
12
public class MyViewModel : NotifyPropertyChanged {
 
   private int _myField;
 
   public int MyProperty {
      get { return _myField; }
      set {
         _myField = value;
         OnPropertyChanged("MyProperty");
      }
   }
}

lambda 表明式实现模式

对 lambda 表明式相比较熟练的同班能够设想用 lambda 表达式实现属性名称传递,
在 NotifyPropertyChanged 类添加一个如此的法门:

1
2
3
4
5
6
7
8
9
10
11
12
13
protected void SetProperty<T>(ref T propField, T value, Expression<Func<T>> expr) {
   var bodyExpr = expr.Body as System.Linq.Expressions.MemberExpression;
   if (bodyExpr == null) {
      throw new ArgumentException("Expression must be a MemberExpression!", "expr");
   }
   var propInfo = bodyExpr.Member as PropertyInfo;
   if (propInfo == null) {
      throw new ArgumentException("Expression must be a PropertyExpression!", "expr");
   }
   var propName = propInfo.Name;
   propField = value;
   this.OnPropertyChanged(propName);
}

有了这多少个措施, NotifyPropertyChanged 基类使用起来就令人神采飞扬了众多:

1
2
3
4
5
6
7
8
9
10
11
public class MyViewModel : NotifyPropertyChanged {
 
   private int _myField;
 
   public int MyProperty {
      get { return _myField; }
      set {
         base.SetProperty(ref _myField, value, () => this.MyProperty);
          }
   }
}

这样一来, 把性能名称用字符串传递改成了用 lambda 表明式传递,
减弱了硬编码, 确实方便了诸多, 但是如故感到略微麻烦了一些,
依然要写一个 lambda 表明式来传递属性名称。

lambda 表明式实现模式

对 lambda 表明式相比熟谙的校友可以设想用 lambda 表明式实现属性名称传递,
在 NotifyPropertyChanged 类添加一个这样的形式:

1
2
3
4
5
6
7
8
9
10
11
12
13
protected void SetProperty<T>(ref T propField, T value, Expression<Func<T>> expr) {
   var bodyExpr = expr.Body as System.Linq.Expressions.MemberExpression;
   if (bodyExpr == null) {
      throw new ArgumentException("Expression must be a MemberExpression!", "expr");
   }
   var propInfo = bodyExpr.Member as PropertyInfo;
   if (propInfo == null) {
      throw new ArgumentException("Expression must be a PropertyExpression!", "expr");
   }
   var propName = propInfo.Name;
   propField = value;
   this.OnPropertyChanged(propName);
}

有了那一个措施, NotifyPropertyChanged 基类使用起来就令人好看了成千上万:

1
2
3
4
5
6
7
8
9
10
11
public class MyViewModel : NotifyPropertyChanged {
 
   private int _myField;
 
   public int MyProperty {
      get { return _myField; }
      set {
         base.SetProperty(ref _myField, value, () => this.MyProperty);
          }
   }
}

这样一来, 把性能名称用字符串传递改成了用 lambda 表明式传递,
裁减了硬编码, 确实方便了成百上千, 不过如故感到略微麻烦了部分,
仍然要写一个 lambda 表明式来传递属性名称。

阻止模式贯彻

假若对 Castal.DynamicProxy 有记忆的话, 能够考虑采纳 DynamicProxy
举办拦阻实现, 我的贯彻如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 1. 先定义一个拦截器, 重写 PostProcess 方法, 当发现是调用以 set_ 开头的方法时,
//    一般就是设置属性了, 可以在这里触发相应的事件。
internal class NotifyPropertyChangedInterceptor : StandardInterceptor {
 
   protected override void PostProceed(IInvocation invocation) {
      base.PostProceed(invocation);
      var methodName = invocation.Method.Name;
      if (methodName.StartsWith("set_")) {
         var propertyName = methodName.Substring(4);
         var target = invocation.Proxy as NotifyPropertyChanged;
         if (target != null) {
            target.OnPropertyChanged(propertyName);
         }
      }
   }
}
 
// 2. 再定义一个帮助类, 提供一个工厂方法创建代理类。
public static class ViewModelHelper {
 
   private static readonly ProxyGenerator ProxyGenerator = new ProxyGenerator();
   private static readonly NotifyPropertyChangedInterceptor Interceptor
         = new NotifyPropertyChangedInterceptor();
 
   public static T CreateProxy<T>(T obj) where T : class, INotifyPropertyChanged {
      return ProxyGenerator.CreateClassProxyWithTarget(obj, Interceptor);
   }
}

运用起来也是很方便的, 只是创设 ViewModel 对象时必须用匡助类来创立实例,
代码如下:

1
2
3
4
5
6
7
8
9
10
public class MyViewModel : NotifyPropertyChanged {
 
   // 定义属性时不需要任何基类方法, 和普通属性没有什么两样。
   public int MyProperty {
      get; set;
   }
}
// 使用时需要这样创建实例:
var viewModel = ViewModelHelper.CreateProxy<MyViewModel>();
viewModel.MyProperty = 100;

然则这种实现的欠缺就是兼备的性能都会触发 PropertyChanged 事件,
而且只能触发一个轩然大波, 而在骨子里支出中, 偶尔需要安装一个特性, 触发多个PropertyChanged 事件。

堵住情势贯彻

尽管对 Castal.DynamicProxy 有记忆的话, 可以设想动用 DynamicProxy
举行拦阻实现, 我的落实如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 1. 先定义一个拦截器, 重写 PostProcess 方法, 当发现是调用以 set_ 开头的方法时,
//    一般就是设置属性了, 可以在这里触发相应的事件。
internal class NotifyPropertyChangedInterceptor : StandardInterceptor {
 
   protected override void PostProceed(IInvocation invocation) {
      base.PostProceed(invocation);
      var methodName = invocation.Method.Name;
      if (methodName.StartsWith("set_")) {
         var propertyName = methodName.Substring(4);
         var target = invocation.Proxy as NotifyPropertyChanged;
         if (target != null) {
            target.OnPropertyChanged(propertyName);
         }
      }
   }
}
 
// 2. 再定义一个帮助类, 提供一个工厂方法创建代理类。
public static class ViewModelHelper {
 
   private static readonly ProxyGenerator ProxyGenerator = new ProxyGenerator();
   private static readonly NotifyPropertyChangedInterceptor Interceptor
         = new NotifyPropertyChangedInterceptor();
 
   public static T CreateProxy<T>(T obj) where T : class, INotifyPropertyChanged {
      return ProxyGenerator.CreateClassProxyWithTarget(obj, Interceptor);
   }
}

行使起来也是很便利的, 只是开创 ViewModel 对象时必须用帮助类来创设实例,
代码如下:

1
2
3
4
5
6
7
8
9
10
public class MyViewModel : NotifyPropertyChanged {
 
   // 定义属性时不需要任何基类方法, 和普通属性没有什么两样。
   public int MyProperty {
      get; set;
   }
}
// 使用时需要这样创建实例:
var viewModel = ViewModelHelper.CreateProxy<MyViewModel>();
viewModel.MyProperty = 100;

不过这种实现的瑕疵就是有所的习性都会触发 PropertyChanged 事件,
而且只好触发一个事件, 而在实际上开发中, 偶尔需要设置一个特性, 触发五个PropertyChanged 事件。

前途 .Net 4.5 的实现格局

在将要发布的 .Net 4.5 中,
提供了 CallerMemberNameAttribute.aspx) 标记,
利用这一个特性, 可以将方面提供的 SetProperty 方法开展改造,
这样的落实才是最完美的:

1
2
3
4
5
6
protected void SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null) {
   if (object.Equals(storage, value)) return;
 
   storage = value;
   this.OnPropertyChanged(propertyName);
}

出于有了 CallerMemberName 标记助阵, 可以说拔取起来是这个便于了:

1
2
3
4
5
6
7
8
9
10
11
public class MyViewModel : NotifyPropertyChanged {
 
   private int _myField;
 
   public int MyProperty {
      get { return _myField; }
      set {
         base.SetProperty(ref _myField, value);
      }
   }
}

这种方法即使好,可是却唯有在 .Net 4.5 中才有, 而且也许永远不会添加到
Silverlight 中。

 

其次步:用户界面绑定数据对象,指定绑定情势

.xaml

<Grid x:Name="LayoutRoot" Background="Wheat" Loaded="LayoutRoot_Loaded">
        <StackPanel>
            <TextBox  Grid.Row="0"  Grid.Column="0" Width="150" Height="30"  HorizontalAlignment="Left" Text="{Binding Name,Mode=OneTime}"/>
            <TextBox  Grid.Row="1"  Grid.Column="0" Width="150" Height="30" HorizontalAlignment="Left" Text="{Binding Age,Mode=OneTime}"/>
            <TextBox  Grid.Row="2"  Grid.Column="0" Width="150" Height="30" HorizontalAlignment="Left" Text="{Binding Address,Mode=OneTime}"/>
            <Button x:Name="btnUpdata" Width="150" Height="30" Content="更新" Click="btnUpdata_Click"/>
        </StackPanel>
    </Grid>

其三步:数据绑定

.xaml.cs

 Person person;
        void LayoutRoot_Loaded(object sender,RoutedEventArgs e)
        {
            person = new Person()
            {
              Name="Terry",
              Age=20,
              Address="Beijing"
            };
            this.LayoutRoot.DataContext = person;
        }

        private void btnUpdata_Click(object sender, RoutedEventArgs e)
        {
            person.Name = "小哥";
            person.Age = 23;
            person.Address = "上海";

        }

 

鉴于是One提姆e数据绑定形式,能够看出在单机更新按钮时,虽然改变了数据对象的属性值,不过用户界面的数据值依然是在绑定成立时候的数据值。

前程 .Net 4.5 的贯彻情势

在快要宣布的 .Net 4.5 中,
提供了 CallerMemberNameAttribute.aspx) 标记,
利用那个特性, 可以将地点提供的 SetProperty 方法开展改造,
这样的兑现才是最周详的:

1
2
3
4
5
6
protected void SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null) {
   if (object.Equals(storage, value)) return;
 
   storage = value;
   this.OnPropertyChanged(propertyName);
}

是因为有了 CallerMemberName 标记助阵, 可以说利用起来是很是方便了:

1
2
3
4
5
6
7
8
9
10
11
public class MyViewModel : NotifyPropertyChanged {
 
   private int _myField;
 
   public int MyProperty {
      get { return _myField; }
      set {
         base.SetProperty(ref _myField, value);
      }
   }
}

这种方法即便好,可是却唯有在 .Net 4.5 中才有, 而且也许永远不会添加到
Silverlight 中。

 

第二步:用户界面绑定数据对象,指定绑定形式

.xaml

<Grid x:Name="LayoutRoot" Background="Wheat" Loaded="LayoutRoot_Loaded">
        <StackPanel>
            <TextBox  Grid.Row="0"  Grid.Column="0" Width="150" Height="30"  HorizontalAlignment="Left" Text="{Binding Name,Mode=OneTime}"/>
            <TextBox  Grid.Row="1"  Grid.Column="0" Width="150" Height="30" HorizontalAlignment="Left" Text="{Binding Age,Mode=OneTime}"/>
            <TextBox  Grid.Row="2"  Grid.Column="0" Width="150" Height="30" HorizontalAlignment="Left" Text="{Binding Address,Mode=OneTime}"/>
            <Button x:Name="btnUpdata" Width="150" Height="30" Content="更新" Click="btnUpdata_Click"/>
        </StackPanel>
    </Grid>

其三步:数据绑定

.xaml.cs

 Person person;
        void LayoutRoot_Loaded(object sender,RoutedEventArgs e)
        {
            person = new Person()
            {
              Name="Terry",
              Age=20,
              Address="Beijing"
            };
            this.LayoutRoot.DataContext = person;
        }

        private void btnUpdata_Click(object sender, RoutedEventArgs e)
        {
            person.Name = "小哥";
            person.Age = 23;
            person.Address = "上海";

        }

 

是因为是One提姆(Tim)e数据绑定格局,可以观察在单机更新按钮时,即使改变了数量对象的属性值,可是用户界面的数据值如故是在绑定创造时候的数据值。