您的当前位置:首页正文

[WPF]Binding查找DataContext的一点问题

2024-11-08 来源:个人技术集锦

按照现在网上关于DataContext的普遍说法,WPF的UI是树状的,每个节点都是控件,所以每个节点都有DataContext属性,如果一个Binding找不到自己的Source那他就会沿着这个UI树一直往上找,直到找到和Path对应的那个属性,如果到最外层也没找到,那就没有数据源。

可我发现好像并不像是这样,下面用一个例子来说明吧。
新建一个类,为Human.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace WpfApplication20190917B
{
    //人类
    class Human
    {
        private string name;//姓名
 
        public string Name
        {
            get { return name; }
            set { name = value; }
        }
 
        private int age;//年龄
 
        public int Age
        {
            get { return age; }
            set { age = value; }
        }
 
        private double height;//身高(单位:cm)
 
        public double Height
        {
            get { return height; }
            set { height = value; }
        }
 
        private double weight;//体重(单位:斤)
 
        public double Weight
        {
            get { return weight; }
            set { weight = value; }
        }
 
        public Human() { }
 
        public Human(string Name, int Age, double Height, double Weight)
        {
            this.name = Name;
            this.age = Age;
            this.height = Height;
            this.weight = Weight;
        }
    }
}

再新建一个类叫Man.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace WpfApplication20190917B
{
    //男人
    class Man : Human
    {
        private double jjLength;//丁丁长度(单位:cm)
 
        public double JjLength
        {
            get { return jjLength; }
            set { jjLength = value; }
        }
 
        public Man()
            : base()
        {
 
        }
 
        public Man(string Name, int Age, double Height, double Weight, double JjLength):base(Name,Age,Height,Weight)
        {
            this.jjLength = JjLength;
        }
    }
}

还得再新建一个类叫Woman.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace WpfApplication20190917B
{
    //女人
    class Woman : Human
    {
        private string cup;//罩杯
 
        public string Cup
        {
            get { return cup; }
            set { cup = value; }
        }
 
        public Woman() : base() { }
 
        public Woman(string Name, int Age, double Height, double Weight, string Cup)
            : base(Name, Age, Height, Weight)
        {
            this.cup = Cup;
        }
    }
}

MainWindow.xaml代码如下

<Window x:Class="WpfApplication20190917B.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid Name="grid1">
        <Grid Name="grid2">
            <Grid.RowDefinitions>
                <RowDefinition></RowDefinition>
                <RowDefinition></RowDefinition>
                <RowDefinition></RowDefinition>
                <RowDefinition></RowDefinition>
                <RowDefinition></RowDefinition>
                <RowDefinition></RowDefinition>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"></ColumnDefinition>
                <ColumnDefinition></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <TextBlock Text="姓名:"/>
            <TextBlock Text="年龄:" Grid.Row="1"/>
            <TextBlock Text="身高:" Grid.Row="2"/>
            <TextBlock Text="体重:" Grid.Row="3"/>
            <TextBlock Text="丁丁长度:" Grid.Row="4"/>
            <TextBlock Text="罩杯:" Grid.Row="5"/>
            <TextBlock Name="name" Text="{Binding Path=Name}" Grid.Column="1"/>
            <TextBlock Name="age" Text="{Binding Path=Age}" Grid.Row="1" Grid.Column="1"/>
            <TextBlock Name="height" Text="{Binding Path=Height}" Grid.Row="2" Grid.Column="1"/>
            <TextBlock Name="weight" Text="{Binding Path=Weight}" Grid.Row="3" Grid.Column="1"/>
            <TextBlock Name="jj_length" Text="{Binding Path=JjLength}" Grid.Row="4" Grid.Column="1"/>
            <TextBlock Name="cup" Text="{Binding Path=Cup}" Grid.Row="5" Grid.Column="1"/>
        </Grid>
    </Grid>
</Window>

MainWindow.xaml.cs代码如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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;
 
namespace WpfApplication20190917B
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            Man man1 = new Man("亚当",25,160.1,130.5,18.3);
            Woman woman1 = new Woman("夏娃",22,155.9,115.0,"B罩");
            this.grid2.DataContext = man1;
            this.grid1.DataContext = woman1;
        }
    }
}

运行结果

上面例子中,grid2绑定了亚当的数据,所以前5个属性是有值的。理论上来说cup这个控件的Binding在grid2.DataContext找不到Cup这一属性,应该会再次往上找啊,再往上是grid1,绑定的是夏娃的数据,应当能够获取值的,实际上并没有。

我猜测Binding去查找DataContext的值应该是这么查找的:只要控件往上找的过程中找到了DataContext不为空的控件就不会再往上找了,不管这个DataContext里面有没有我需要的属性。

为了进一步验证,我们在MainWindow.xaml.cs多加一行代码

Woman woman2 = new Woman("柳岩", 39, 162.0, 104.3, "G罩");
this.jj_length.DataContext = woman2;

也就是给jj_length这个控件设置了DataContext,运行效果如下

最后,把MainWindow.xaml.cs代码改成如下,来看一看效果

Man man1 = new Man("亚当",25,160.1,130.5,18.3);
Woman woman1 = new Woman("夏娃",22,155.9,115.0,"B罩");
this.grid2.DataContext = man1;
this.grid1.DataContext = woman1;

Woman woman2 = new Woman("柳岩", 39, 162.0, 104.3, "G罩");
this.cup.DataContext = woman2;

显示全文