上一篇我们将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. 移动端1px边框

    问题:移动端1px边框,看起来总是2倍的边框大小,为了解决这个问题试用过很多方法,用图片,用js判断dpr等,都不太满意, 最后找到一个还算好用的方法:伪类 + transform 原理是把原先元素的 ...

  2. UWP开发之Mvvmlight实践六:MissingMetadataException解决办法(.Net Native下Default.rd.xml配置问题)

    最近完成一款UWP应用,在手机端测试发布版(Release)的时候应用莫名奇妙的强行关闭,而同样的应用包在PC端一点问题都没有,而且Debug版在两个平台都没有问题,唯独手机的Release版有问题. ...

  3. git克隆项目到本地&&全局安装依赖项目&&安装依赖包&&启动服务

     一.安装本地开发环境 1.安装本项目 在需要保存到本地的项目的文件夹,进入到文件夹里点击右键,bash here,出现下图: 2.安装依赖项目  3.安装依赖包(进入到命令行) # 安装依赖包 $ ...

  4. 解构C#游戏框架uFrame兼谈游戏架构设计

    1.概览 uFrame是提供给Unity3D开发者使用的一个框架插件,它本身模仿了MVVM这种架构模式(事实上并不包含Model部分,且多出了Controller部分).因为用于Unity3D,所以它 ...

  5. vs15 preview5 离线安装包

    1.介绍 vs15是微软打造的新一代IDE,全新的安装方式.官网介绍如下(https://blogs.msdn.microsoft.com/visualstudio/2016/10/05/announ ...

  6. C#反序列化XML异常:在 XML文档(0, 0)中有一个错误“缺少根元素”

    Q: 在反序列化 Xml 字符串为 Xml 对象时,抛出如下异常. 即在 XML文档(0, 0)中有一个错误:缺少根元素. A: 首先看下代码: StringBuilder sb = new Stri ...

  7. 初识JavaScript

    JavaScript ECMA-262: 变量,函数,对象,数据类型....唯独没有输入和输出. Javascript:包含 ECMA-262,核心 BOM 浏览器对象模型, DOM 文档对象模型 什 ...

  8. Javascript学习笔记

    Javascript 2016年12月19日整理 JS基础 Chapter1 JS是一门运行在浏览器客户端的脚本编程语言,前台语言 组成部分 1. ECMAscript JS标准 2. DOM 通过J ...

  9. mysql百万级分页优化

    普通分页 数据分页在网页中十分多见,分页一般都是limit start,offset,然后根据页码page计算start , 这种分页在几十万的时候分页效率就会比较低了,MySQL需要从头开始一直往后 ...

  10. sql server 取文件名函数 转载

    /****** Object: UserDefinedFunction [dbo].[GetDirectoryPath] Script Date: 2016-12-16 16:54:05 ****** ...