上一篇我们将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路由事件的相关内容

WPF入门:数据绑定的更多相关文章

  1. WPF入门教程系列十五——WPF中的数据绑定(一)

    使用Windows Presentation Foundation (WPF) 可以很方便的设计出强大的用户界面,同时 WPF提供了数据绑定功能.WPF的数据绑定跟Winform与ASP.NET中的数 ...

  2. WPF入门教程系列二十三——DataGrid示例(三)

    DataGrid的选择模式 默认情况下,DataGrid 的选择模式为“全行选择”,并且可以同时选择多行(如下图所示),我们可以通过SelectionMode 和SelectionUnit 属性来修改 ...

  3. WPF入门教程系列三——Application介绍(续)

    接上文WPF入门教程系列二——Application介绍,我们继续来学习Application 三.WPF应用程序的关闭 WPF应用程序的关闭只有在应用程序的 Shutdown 方法被调用时,应用程序 ...

  4. WPF入门教程系列二——Application介绍

    一.Application介绍 WPF和WinForm 很相似, WPF与WinForm一样有一个 Application对象来进行一些全局的行为和操作,并且每个 Domain (应用程序域)中仅且只 ...

  5. WPF入门教程系列(二) 深入剖析WPF Binding的使用方法

    WPF入门教程系列(二) 深入剖析WPF Binding的使用方法 同一个对象(特指System.Windows.DependencyObject的子类)的同一种属性(特指DependencyProp ...

  6. WPF入门教程系列(一) 创建你的第一个WPF项目

    WPF入门教程系列(一) 创建你的第一个WPF项目 WPF基础知识 快速学习绝不是从零学起的,良好的基础是快速入手的关键,下面先为大家摞列以下自己总结的学习WPF的几点基础知识: 1) C#基础语法知 ...

  7. WPF入门教程系列一

    WPF入门教程 一.  前言  公司项目基于WPF开发,最近项目上线有点空闲时间写一篇基于wpf的基础教材,WPF也是近期才接触,学习WPF也是在网上查资料与微软的MSDN进行学习,写本博客的目为了温 ...

  8. WPF入门(四)->线形区域Path内容填充之填充图(ImageBrush)

    原文:WPF入门(四)->线形区域Path内容填充之填充图(ImageBrush) 前面我们提到了LinearGradientBrush可以用来画渐变填充图,那么我们同时也可以使用ImageBr ...

  9. WPF入门(四)->线形区域Path内容填充之渐变色(LinearGradientBrush)

    原文:WPF入门(四)->线形区域Path内容填充之渐变色(LinearGradientBrush) 前面我们介绍到,Path对象表示一个用直线或者曲线连接的图形,我们可以使用Path.Data ...

随机推荐

  1. ASP.NET MVC5+EF6+EasyUI 后台管理系统(67)-MVC与ECharts

    系列目录 ECharts 特性介绍 ECharts,一个纯 Javascript 的图表库,可以流畅的运行在 PC 和移动设备上,兼容当前绝大部分浏览器(IE8/9/10/11,Chrome,Fire ...

  2. 6. ModelDriven拦截器、Preparable 拦截器

    1. 问题 Struts2 的 Action 我们将它定义为一个控制器,但是由于在 Action 中也可以来编写一些业务逻辑,也有人会在 Action 输入业务逻辑层. 但是在企业开发中,我们一般会将 ...

  3. DBSCAN密度聚类算法

    DBSCAN(Density-Based Spatial Clustering of Applications with Noise,具有噪声的基于密度的聚类方法)是一种很典型的密度聚类算法,和K-M ...

  4. C# BackgroundWorker 详解

    在C#程序中,经常会有一些耗时较长的CPU密集型运算,如果直接在 UI 线程执行这样的运算就会出现UI不响应的问题.解决这类问题的主要途径是使用多线程,启动一个后台线程,把运算操作放在这个后台线程中完 ...

  5. ESLint的使用笔记

    原文地址:https://csspod.com/getting-started-with-eslint/?utm_source=tuicool&utm_medium=referral 在团队协 ...

  6. angular2之前端篇—1(node服务器分支)

    上一篇.net core和angular2之前端篇-1 使用的是dotnet模板.之所以用它,因为想用他写webapi,但是写道下一篇的时候遇到点问题,所以先写个分支测试一下.这次是用Node作为服务 ...

  7. ubuntu安装mysql

    好记性不如烂笔头,记录一下,ubuntu安装mysql的指令. 安装MySQL: sudo apt-get install mysql-server sudo apt-get install mysq ...

  8. 初学DirectX11, 留个纪恋。

    以前学的是openGL, 最近才开始学DirectX11,写了个很垃圾的代码,怀念以前的glPushMatrix(), glPopMatrix(), glBegin(), glEnd(), 多简单啊, ...

  9. maven常见异常以及解决方法

    本文写的是我在整合ssm框架时遇到的一些问题,我估计很多人也会遇到,所以,这里作为一个总结,希望能够帮助大家解决问题 一,加入shiro组件时抛出的异常 加入步骤(略) 问题 1,保存后,无法导入sh ...

  10. Angular2笔记:NgModule

    Angular的模块的目的是用来组织app的逻辑结构. 在ng中使用@NgModule修饰的class就被认为是一个ng module.NgModule可以管理模块内部的Components.Dire ...