WPF入门:数据绑定

2016-12-10 19:34:13来源:cnblogs.com作者:流年、落了誰人点击

第七城市

上一篇我们将XAML大概做了个了解 ,这篇将继续学习WPF数据绑定的相关内容

数据源与控件的Binding

Binding作为数据传送UI的通道,通过INotityPropertyChanged接口的PropertyChanged事件通知Binding数据属性发生改变

  public class Product : INotifyPropertyChanged  {      private string name;      public string Name      {          get { return name; }          set          {              name = value;              if (PropertyChanged != null)              {                  this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Name"));              }          }      }      public event PropertyChangedEventHandler PropertyChanged;  }

通过Binding关联UI控件元素

   this.txtOfProduct.SetBinding(TextBox.TextProperty, new Binding() { Path = new PropertyPath("Name"), Source = p });

控件之间的Binding

 <TextBox x:Name="TextBox1" Text="{Binding ElementName=slider1,Path=Value,Mode=OneWay}"></TextBox> <Slider x:Name="slider1" Margin="5"></Slider>


我们也可以通过后台C#代码实现

 TextBox1.SetBinding(TextBox.TextProperty, new Binding("Value") { ElementName = "slider1", Mode=BindingMode.OneWay });

统计文本字符长度

 <TextBox x:Name="TextBox1"  Margin="5"  TextWrapping="Wrap" ></TextBox> <TextBlock Margin="5"  TextAlignment="Right" Text="{Binding ElementName=TextBox1, Path=Text.Length}"></TextBlock>

Binding的Path

Path的索引器方式

  <TextBox x:Name="TextBox1"  Margin="5"  TextWrapping="Wrap" ></TextBox>  <!--获取Text的第三个字符-->  <TextBlock Margin="5"  TextAlignment="Right" Text="{Binding ElementName=TextBox1, Path=Text.[2]}"></TextBlock>  <TextBlock Margin="5"  TextAlignment="Right" Text="{Binding ElementName=TextBox1, Path=Text[2]}"></TextBlock>

当使用一个集合或者DataView作为Binding源时,如果我们想把它的默认元素作为Path来使用

 List<string> names = new List<string>() { "张三", "李四", "王五" }; //张三 this.TextBox1.SetBinding(TextBox.TextProperty, new Binding("/") { Source = names }); //“张三”字符串的长度 this.TextBox2.SetBinding(TextBox.TextProperty, new Binding("/Length") { Source = names,Mode=BindingMode.OneWay}); //获取“张三”字符串中的第1个字符 this.TextBox3.SetBinding(TextBox.TextProperty, new Binding("/[0]") { Source = names, Mode = BindingMode.OneWay });

如果集合中嵌套集合,我们依然可以通过多级"/"语法把子集作为Path的元素

  class City  {      public string Name { get; set; }  }  class Province  {      public List<City> Citys { get; set; }      public string Name { get; set; }  }  class Country  {      public List<Province> Provinces { get; set; }      public string Name { get; set; }  }
  TextBox1.SetBinding(TextBox.TextProperty, new Binding("/Name") { Source = countries });  TextBox2.SetBinding(TextBox.TextProperty, new Binding("/Provinces/Name") { Source = countries });  TextBox3.SetBinding(TextBox.TextProperty, new Binding("/Provinces/Citys/Name") { Source = countries });

省略Path

sys需要引用xmlns:sys="clr-namespace:System;assembly=mscorlib"

 <StackPanel.Resources>     <sys:String x:Key="text">         WPF入门手册     </sys:String> </StackPanel.Resources> <TextBox x:Name="TextBox1"  Margin="5" Text="{Binding .,Source={StaticResource ResourceKey=text}}" ></TextBox>
TextBox2.SetBinding(TextBox.TextProperty, new Binding(".") { Source = "WPF技术入门" });

没有Path和Source,Binding可以通过DataContext获取数据

 <StackPanel.DataContext>     <sys:String>         WPF入门手册     </sys:String> </StackPanel.DataContext> <TextBox x:Name="TextBox1"  Margin="5" Text="{Binding Mode=OneWay}" ></TextBox>

选中ListBox元素显示对应的属性的一个例子

 <TextBox x:Name="TextBox1"  Margin="5" ></TextBox> <ListBox x:Name="ListBox1"></ListBox>
  List<City> cities = new List<City>() {      new City() { Id=1,Name="北京" },      new City() { Id=2,Name="昆明" },      new City() { Id=3,Name="上海" },      new City() { Id=4,Name="厦门" },      new City() { Id=5,Name="广州" }  };  this.ListBox1.ItemsSource = cities;  this.ListBox1.DisplayMemberPath = "Name";  this.TextBox1.SetBinding(TextBox.TextProperty, new Binding("SelectedItem.Id") { Source = this.ListBox1 });

使用Binding的RelativeSource

Binding有明确的数据源的时,我们可以通过SoureElementName赋值办法关联Binding,但有事我们不知道Soure对象的名字是什么,却知道它与作为Binding目标对象的UI元素布局上的相对关系,通过RelativeSourceMode枚举设置关联的对象关系

<Grid x:Name="g1">    <StackPanel x:Name="s1">        <DockPanel x:Name="d1">            <TextBox x:Name="TextBox1"  Margin="5" ></TextBox>        </DockPanel>    </StackPanel></Grid>

后台代码处理

 RelativeSource rs = new RelativeSource(RelativeSourceMode.FindAncestor) {     AncestorLevel = 1,     AncestorType = typeof(StackPanel) }; //将StackPanel的Name s1赋给了TextBox1的Text TextBox1.SetBinding(TextBox.TextProperty, new Binding("Name") { RelativeSource = rs });

也可以通过XAML的方式赋值

    <Grid x:Name="g1">        <StackPanel x:Name="s1">            <DockPanel x:Name="d1">                <TextBox x:Name="TextBox1"  Margin="5" Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type DockPanel},AncestorLevel=1,Mode=FindAncestor}, Path=Name}" ></TextBox>            </DockPanel>        </StackPanel>    </Grid>

Binding数据验证

BindingValidationRules属性的类型为Collection<ValidationRule>。通过实现Validate方法返回给ValidationResult对象,并设置IsVaild属性,ErrorContent属性可以接受一个字符串。

 public class RangValidationRule : ValidationRule {     //验证数据     public override ValidationResult Validate(object value, CultureInfo cultureInfo)     {         double d = 0;         if (double.TryParse(value.ToString(), out d))         {             if (d >= 1 && d <= 100)             {                 return new ValidationResult(true, null);             }         }         return new ValidationResult(false, "数据错误");     } }
 <TextBox x:Name="TextBox1" Margin="5"></TextBox> <Slider x:Name="slider1" Minimum="1" Maximum="100" Margin="5"></Slider>
 Binding binding = new Binding("Value") {     Source=slider1,     UpdateSourceTrigger=UpdateSourceTrigger.PropertyChanged, }; binding.ValidationRules.Add(new RangValidationRule()); this.TextBox1.SetBinding(TextBox.TextProperty, binding);

显示错误提示

  public MainWindow()  {      InitializeComponent();      Binding binding = new Binding("Value")      {          Source = slider1,          UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,          NotifyOnValidationError = true//开启错误通知      };      binding.ValidationRules.Add(new RangValidationRule());      this.TextBox1.SetBinding(TextBox.TextProperty, binding);       //注册验证错误事件      this.TextBox1.AddHandler(Validation.ErrorEvent, new RoutedEventHandler(ValidationErrorNotify));  }  private void ValidationErrorNotify(object sender, RoutedEventArgs e)  {      var errors = Validation.GetErrors(this.TextBox1);      if (errors.Count > 0)      {          TextBlock1.Text = errors[0].ErrorContent.ToString();      }  }

多路Binding

一般我们在做注册用户功能的时候,输入密码的时候都需要再确认输入密码,比较两次输入是否一致,现在我们可以通过多路Binding来简单的实现这个功能
首先实现一个IMultiValueConverter接口功能,如果两次密码一致,提交按钮状态为可用

    public class SubmitMultiBindingConverter : IMultiValueConverter    {        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)        {            return (!values.Cast<string>().Any(a => string.IsNullOrEmpty(a))/*验证所有元素非空*/ &&                values[0].ToString() == values[1].ToString())/*值1=值2*/;                    }        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)        {            throw new NotImplementedException();        }    }

XAML代码

 <TextBox x:Name="Password" Margin="5"></TextBox> <TextBox x:Name="Passworder" Margin="5"></TextBox> <Button x:Name="Submit" Content="提交" Margin="10" Height="30" Width="100"></Button>

后台Binding

 Binding pwdBinding = new Binding("Text") { Source = Password }; Binding pwderBinding = new Binding("Text") { Source = Passworder }; MultiBinding multi = new MultiBinding() { Mode=BindingMode.OneWay}; multi.Bindings.Add(pwdBinding); multi.Bindings.Add(pwderBinding); multi.Converter = new SubmitMultiBindingConverter(); Submit.SetBinding(Button.IsEnabledProperty, multi);


以上就是Binding常用到的功能,下篇我将继续学习依赖属性和WPF路由事件的相关内容


第七城市

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台