WPF基础学习 —— 2

参考书籍《深入浅出WPF》,原书第6章节学习笔记整理。
程序的本质是数据+算法

Binding基础

Binding是一座桥梁,它的源是逻辑层的对象、它的目标是UI层的控件对象。这样数据会不断的通过Binding送达UI层,被UI层展现。

1、属性

创建一个简单的类对象作为数据源,设置将类中的参数属性通过Binding传递给UI控件,则该属性即为路径(Path)。
除此之外,当属性值发生变化后需要自动通知Binding,将变化的数值传递给UI控件。

  • 在属性的set语句中激发一个PropertyChanged事件
  • 作为数据源的实现System.ComponentModel中的INotifyPropertyChanged接口

当为Bing设置了数据源后,会自动侦听来自该接口的PropertyChanged事件

2、代码

注意:粘贴xml代码时,上半部分xmls不能粘贴,他是针对具体的工程建立的。

<Window 
        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" mc:Ignorable="d" x:Class="WpfApplication1_8_18.MainWindow"
        Title="Simple Binding" Height="110" Width="300" >
    <StackPanel>
        <TextBox x:Name="textBoxName" BorderBrush="Black" Margin="5"/>
        <Button Content="Add Name" Margin="5" Click="Button_Click"/>
    </StackPanel>
</Window>

窗体界面显示如下:
在这里插入图片描述

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;//以上为程序自动添加的引用
//以下为额外添加引用
using System.ComponentModel;//添加引用

class Student : INotifyPropertyChanged //让作为数据源的Student类实现System.ComponentModel空间的INotifyPropertyChanged接口
{
   
    public event PropertyChangedEventHandler PropertyChanged; //句柄
    private string name;  //Student类里面的局部变量
    public string Name
    {
   
        get {
    return name;}
        set
        {
   
            name = value;//value?
            //激发事件
            if(this.PropertyChanged!=null)
            {
   
                this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Name"));
            }
        }
    }
}

namespace WpfApplication1_8_18
{
   
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
 
    public partial class MainWindow : Window
    {
   
        Student stu ;
        
        public MainWindow()
        {
   
            InitializeComponent();
            //准备数据源
            stu = new Student();
            //准备Binding
            Binding binding = new Binding();
            binding.Source = stu;   //为Binding指定数据源
            binding.Path = new PropertyPath("Name");  //为Binding指定访问路径
            //使用Binding连接数据源与Binding目标:(目标,送达目标的哪个属性,使用的Binding实例)
            BindingOperations.SetBinding(this.textBoxName, TextBox.TextProperty, binding);
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
   
            //使用Binding把数据源和UI元素连接起来
            stu.Name += "Name";
        }      
    }    
}

程序运行效果如下:
在这里插入图片描述

3、整个程序运行的流程如下:

在这里插入图片描述

4、借助Binding构造器进行简化

在这里插入图片描述

Binding的源
把控件作为Binding源

为了让UI产生一些联动效果,会用Binding在控件之间建立关联。

<Window 
        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" mc:Ignorable="d" x:Class="WpfApplication1_8_18.MainWindow"
        Title="Control as Source" Height="110" Width="300" >
    <StackPanel>
        <TextBox x:Name="textbox1" Text="{Binding Path=Value, ElementName=Slider1}" BorderBrush="Black" Margin="5"/>
        <Slider x:Name="Slider1" Maximum="100" Minimum="0" Margin="5"/>
    </StackPanel>
</Window>

在这里插入图片描述
上述程序中Binding的其它等价形式
语句:

<TextBox x:Name="textbox1" Text="{Binding Path=Value, ElementName=Slider1}" BorderBrush="Black" Margin="5"/>

等价于

<TextBox x:Name="textbox1" BorderBrush="Black" Margin="5"/>
this.textbox1.SetBinding(TextBox.TextProperty, new Binding("Value") {
    ElementName = "Slider1" });
控制Binding的方向及数据更新

默认情况下为双向的。当控件只可读,不可修改时就需要设置为单向。
控制Binding数据流向为Mode:

  • TwoWay
  • OneWay
  • OnTime
  • OneWayToResource
  • Default

上述示例中,滑动Slider则TextBox会显示当前值。反之,在TextBox中输入数值(输入50,按下Tab键使焦点离开TextBox),Slider也会滑动到相应位置。

设置为OneWay之后:滑动Slider则TextBox会改变显示值,但是在TextBox中输入数值之后Slider不会滑动了。

<Window 
        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" mc:Ignorable="d" x:Class="WpfApplication1_8_18.MainWindow"
        Title="Control as Source" Height="110" Width="300" >
    <StackPanel>
        <TextBox x:Name="textbox1" Text="{Binding Path=Value, ElementName=Slider1,Mode=OneWay}" BorderBrush="Black" Margin="5"/>
        <Slider x:Name="Slider1" Maximum="100" Minimum="0" Margin="5"/>
    </StackPanel>
</Window>
//等价的C#命令
this.textbox1.SetBinding(TextBox.TextProperty, new Binding("Value") {
    Source = this.textbox1, Mode = BindingMode.OneWay });

ps:TextBox失去焦点之后Slider才会移动,是因为默认Binding属性UpdateSourceTrigger:
包含了PropertyChanged、LostFocus、Explicit和Default。而TextBox的默认行为与LostFocus一致,当修改为PropertyChanged,则Slider位置会即刻改变。

<Window 
        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" mc:Ignorable="d" x:Class="WpfApplication1_8_18.MainWindow"
        Title="Control as Source" Height="110" Width="300" >
    <StackPanel>
        <TextBox x:Name="textbox1" Text="{Binding Path=Value, ElementName=Slider1,UpdateSourceTrigger=PropertyChanged}" BorderBrush="Black" Margin="5"/>
        <Slider x:Name="Slider1" Maximum="100" Minimum="0" Margin="5"/>
    </StackPanel>
</Window>

pps: Binding还有NotifyOnSourceUpdated和NotifyOnTargetUpdated这2个bool类型属性,如果设为true,当源或者目标被更新后Binding会激发相应的SourceUpdated和TargetUpdated事件,可以通过监听这2个事件来找出有哪些数据源或者控件更新了。

Binding的路径Path

源对象有很多属性,Path决定Binding需要关注哪个属性。各种Path创建方式:

  • 最简单的方式:
 <TextBox x:Name="textbox1" Text="{Binding Path=Value, ElementName=Slider1}" BorderBrush="Black" Margin="5"/>

等价的C#:

 Binding binding = new Binding() {
   Path=new PropertyPath("Value"),Source=this.Slider1 };
 this.textbox1.SetBinding(TextBox.TextProperty, binding);
 //或者使用Binding构造器
 Binding binding = new Binding("Value") {
    Source = this.Slider1 };
 this.textbox1.SetBinding(TextBox.TextProperty, binding);
  • 集合中的索引器作为Path
<Window 
        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" mc:Ignorable="d" x:Class="WpfApplication1_8_18.MainWindow"
        Title="Control as Source" Height="110" Width="300" >
    <StackPanel>
        <TextBox x:Name="textbox1" BorderBrush="Black" Margin="5"/>
        <TextBox x:Name="textbox2" Text="{Binding Path=Text.[3], ElementName=textbox1, Mode=OneWay}" BorderBrush="Black" Margin="5"/>
        <!--上面的语句中Mode=OneWay必须填写,否则会报错-->
    </StackPanel>
</Window>

在这里插入图片描述

//等价的C#语句,不同之处:此处用Source 、BindingMode
this.textbox2.SetBinding(TextBox.TextProperty, new Binding("Text.[3]") {
    Source = this.textbox1, Mode = BindingMode.OneWay });
  • 集合或者DataView的默认元素作为Path
<Window 
        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" mc:Ignorable="d" x:Class="WpfApplication1_8_18.MainWindow"
        Title="Control as Source" Height="120" Width="300" >
    <StackPanel>
        <TextBox x:Name="textbox1" BorderBrush="Black" Margin="5"/>
        <TextBox x:Name="textbox2"  BorderBrush="Black" Margin="5"/>
        <TextBox x:Name="textbox3" BorderBrush="Black" Margin="5"/>
    </StackPanel>
</Window>
//string_list 的默认元素为[0]=Tim
List<string> string_list = new List<string>() {
    "Tim", "Tom", "Tic" };
this.textbox1.SetBinding(TextBox.TextProperty, new Binding("/") {
    Source = string_list });
this.textbox2.SetBinding(TextBox.TextProperty, new Binding("/Length") {
    Source = string_list, Mode = BindingMode.OneWay });
this.textbox3.SetBinding(TextBox.TextProperty, new Binding("/[2]") {
    Source = string_list, Mode = BindingMode.OneWay });

在这里插入图片描述

  • 子级集合中元素作为Path——使用多级/
<Window 
        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" mc:Ignorable="d" x:Class="WpfApplication1_8_18.MainWindow"
        Title="Control as Source" Height="120" Width="300" >
    <StackPanel>
        <TextBox x:Name="textbox1" BorderBrush="Black" Margin="5"/>
        <TextBox x:Name="textbox2"  BorderBrush="Black" Margin="5"/>
        <TextBox x:Name="textbox3" BorderBrush="Black" Margin="5"/>
    </StackPanel>
</Window>
class City
{
   
    public string Name {
    get; set; }
}

class Province
{
   
    public string Name {
    get; set; }
    public List<City> CityList {
    get; set; }
}

class Country
{
   
    public string Name {
    get; set; }
    public List<Province> ProvinceList {
    get; set; }
}

namespace WpfApplication1_8_18
{
   
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
 
    public partial class MainWindow : Window
    {
          
        public MainWindow()
        {
   
            InitializeComponent();

            //Binding
            List<Country> countryList = new List<Country> 
            {
    
                //初始化嵌套类
               new Country(){
   Name="China",ProvinceList=new List<Province>(){
   new Province(){
    Name="HeBei", CityList=new List<City>(){
   new City(){
   Name="BeiJing" },new City(){
   Name="ShiJiaZhuang"} }}}},
               new Country(){
   },//多个Country类之间的书写方式,里面内容省略..
               new Country(){
   }
            };
            this.textbox1.SetBinding(TextBox.TextProperty, new Binding("/Name") {
    Source = countryList });
            this.textbox2.SetBinding(TextBox.TextProperty, new Binding("/ProvinceList/Name") {
    Source = countryList });
            //应为"/ProvinceList[0].Name",教材中给出的"/ProvinceList.Name",但是运行后并无结果输出
            this.textbox3.SetBinding(TextBox.TextProperty, new Binding("/ProvinceList/CityList/Name") {
    Source = countryList });
            //应为:"/ProvinceList/CityList[1].Name",教材中给出的"/ProvinceList/CityList.Name",但是运行后并无结果输出    
        }   
    }    
}

程序运行结果如下:

在这里插入图片描述

此处默认显示“BeiJing”至于怎么显示“ShiJiaZhuang”??

//将显示命令由"/ProvinceList/CityList/Name"修改为"/ProvinceList/CityList[1].Name"即可
this.textbox3.SetBinding(TextBox.TextProperty, new Binding("/ProvinceList/CityList[1].Name") {
    Source = countryList }); 

在这里插入图片描述

其中,嵌套类的初始化方法

//对一个class的正确赋值方法
List<City> city_1 = new List<City>() {
    new City() {
    Name = "city_a" }, new City {
    Name = "city_b" } };
//country的赋值方法
List<Country> countryList = new List<Country> ()
{
    
    new Country(){
   Name="China",ProvinceList=new List<Province>(){
   new Province(){
    Name="HeBei", CityList=new List<City>(){
   new City(){
   Name="BeiJing" },new City(){
   Name="ShiJiaZhuang"} }}}},
    new Country(){
   },//需要初始化多个Country的示例
    new Country(){
   }
};
没有Path的Binding

Binding源本身就是数据且不需要path来指明,如string 、int。
这里书本中写的不明确,导致第一次没有出来效果。这里的sys是一个映射名,在Windows开始标签内定义。

<Window x:Class="WpfApplication1_8_26_1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        Title="MainWindow" Height="200" Width="300">
    <StackPanel>
        <StackPanel.Resources>
            <sys:String x:Key="myString">
                菩提本无树,明镜亦非台。
                本来无一物,何处惹尘埃。
            </sys:String>
        </StackPanel.Resources>
        <TextBlock x:Name="textBlock1" TextWrapping="Wrap" Text="{Binding Path=.,Source={StaticResource ResourceKey=myString}}" FontSize="16" Margin="5"/>
    </StackPanel>
</Window>

在这里插入图片描述
上面的代码也可以简写成:

<TextBlock x:Name="textBlock1" Text="{Binding.,Source={StaticResource ResourceKey=myString}}"/>
//或者
<TextBlock x:Name="
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值