阅读 95

WPF 基础 - Binding 的源与路径

1. 源与路径

  1. 把控件作为 binding 源与 binding 标记拓展;
  2. 控制 Binding 的方向及数据更新;
  3. Binding 的路径 Path;
  4. 没有路径的 Binding;
  5. 为 Binding 指定源的几种方法;
  6. 没有 Source 的 Binding;
  7. 使用集合对象作为列表控件的 ItemsSource;
  8. 使用 ADO.NET 对象作为 Binding 的源;
  9. 使用 XML 的数据作为 Binding 的源;
  10. 使用 LINQ 的检索结果作为 Binding 的源:
  11. 使用 ObjectDataProvider 对象作为 Binding 的 Source;
  12. 使用 Binding 的 RelativeSource;

Binding 作为数据的桥梁,两端分别是源 (Source) 和目标 (Target),同时 Target 作为对象可能会有多个属性值,通过 路径 (Path) 指定通过 Binding 送达 UI 元素的属性;
source:可以为集合对象、ADO.NET 对象、XML 数据、LINQ 检索结果、ObjectDataProvider 对象等;

1.1 把控件作为 binding 源与 binding 标记拓展






//等价于后台:
this.textBlock.SetBinding(TextBlock.TextProperty, new Binding("Value") { ElementName = "slider" });

1.2 控制 Binding 的方向及数据更新

Binding 的属性 Mode 的枚举值决定 Binding 的更新方向:

  • OneWay
  • OneWayToSource
  • OneTime
  • TwoWay
  • Default :不同控件的默认值不一样,比如文本框和复选框默认双向绑定,TextBlock 单向

Binding 的属性 UpdateSourceTrigger 的枚举值决定 Binding 的触发数据更新的条件:

  • Explicit :调用 System.Windows.Data.BindingExpression.UpdateSource 方法时才更新
  • PropertyChanged
  • LostFocus
  • Default : 大多数默认值是 PropertyChanged,而 System.Windows.Controls.TextBox.Text 是 LostFocus

NotifyOnSourceUpdated、NotifyOnTargetUpdated bool值
当值从绑定目标传输到绑定源时是否引发 System.Windows.Data.Binding.SourceUpdated 事件;
当值从绑定源传输到绑定目标时是否引发 System.Windows.Data.Binding.TargetUpdated 事件。
如下面例子:修改 slider 的值,引发 TargetUpdated 事件;
修改 textBox 的值,引发 SourceUpdated 事件;可以记录。


1.3 Binding 的路径 Path

除了上面所说,还支持多级路径


//等价于:
this.textBox2.SetBinding(TextBox.TextProperty, new Binding("Text.Length") { Source = this.textBox, Mode = BindingMode.OneWay });



List stringList = new List() { "Bob", "Long" };
this.xx1.SetBinding(TextBox.TextProperty, new Binding("/") { Source = stringList });//Bob
this.xx2.SetBinding(TextBox.TextProperty, new Binding("/Length") { Source = stringList, Mode = BindingMode.OneWay });//3
this.xx3.SetBinding(TextBox.TextProperty, new Binding("/[2]") { Source = stringList, Mode = BindingMode.OneWay });//b

1.4 没有路径的 Binding

比如 int,string 等本身就是数据,因此用 Path=. 来表示,在 xaml 中可以省略,在 C# 中不能省略


    悟空的小脾气







this.knowNull.SetBinding(TextBlock.TextProperty, new Binding(".") { Source = this.FindResource("myString")});

// 4 个 TextBlock 都展示 "悟空的小脾气"

1.5 没有 Source 的 Binding

1.5.1 无 Source 的 Binding

当一个 Binding 只知道自己的 Path,而不知自己的 Source 时,会沿着 UI 元素树一层一层树的根部找过去,直到找到有设置 DataContext 的元素。


    
        
            
        
        
            
                
                
            
        
    

1.5.2 无 Path 无 Source 的 Binding


    
        
            Hello~
        
        
            
                
            
        
    

1.5.3 测试 DataContext 往下传递


    
        
    
    
        
            
        
        
        
        
    

// 6
// ball
// (空)

把 StackPanel 的 DataContext 去掉
// 1000
// (空)
// 100

1.6 使用集合对象作为列表控件的 ItemsSource

  • 当我们没有为 ListBox 的 ItemTemplate 指定 DataTemplate 时,
    ListBox 在获得 ItemsSource 后会创建等量的 ListBoxItem 并自动设置 DataTemplate。
  • 在获取 DataTemplate 的过程中会以 DisplayMemberPath 属性值作为 Path 创建 Binding。
  • Binding 的目标是 ListBoxItem 的内容插件(TextBox)

1.7 使用 ADO.NET 对象作为 Binding 的源




    
        
            
            
            
        
    


DataView dataView {get;set;}//再添加更新通知。
System.Data.DataTable dt = this.Load();
dataView = dt.DefaultView;

并不能展示数据,但行数是正确的。

1.8 使用 XML 的数据作为 Binding 的源

前面提 x:XData 时有实现过一次 ListBox 绑定到 XmlDataProvider 的方式;

           

这次提供 C# 版;

XmlDataProvider xdp = new XmlDataProvider();
xdp.Source = new Uri(@"D:\RawData.xml");
xdp.XPath = @"/StudentList/Student";

this.listbox.DataContext = xdp;
this.listbox.SetBinding(ListView.ItemsSourceProperty, new Binding());

设置 XmlDataProvider.Source 的效果等同于 XmlDataProvider.Document:

xdp.Source = new Uri(@"D:\RawData.xml");
=
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.Load(@"D:\RawData.xml");
xdp.Document = doc;

1.9 使用 LINQ 的检索结果作为 Binding 的源

1.9.1 LINQ from List


    
        
            
            
        
    


...

List listStr = new List()
{
    new Student() { Id = "11", Name = "YaoMing"},
    new Student() { Id = "24", Name = "Kobe"},
    new Student() { Id = "8", Name = "Kobe-Young"},
};
listViewStrs.ItemsSource = from str in listStr where str.Name.StartsWith("K") select str;

1.9.2 LINQ + XML

listbox.ItemsSource = 
    from element in xdoc.Descendants("Student")
    where element.Attribute("Name").Value.StartsWith("T")
    select new Student()
    {
        Id = int.Parse(element.Attribute("Id").Value),
        Name = element.Attribute("Name").Value
    };

1.9.3 LINQ + DataTable

listbox.ItemsSource = 
    from row in dt.Row.Cast()
    where Convert.ToString(row["Name"]).StartsWith("T") 
    select new Student()
    {
        Id = int.Parse(row["Id"].ToString()),
        Name = row["Name"].ToString()
    };

1.10 使用 ObjectDataProvider 对象作为 Binding 的 Source

1.10.1 介绍一波 ObjectDataProvider

class Calculator
{
    public string Add(string arg1, string arg2)
    {
        double x = 0;
        double y = 0;
        double z = 0;

        if (double.TryParse(arg1, out x) && double.TryParse(arg2, out y))
        {
            z = x + y;
            return z.ToString();
        }

        return "Input Error";
    }
}

ObjectDataProvider dp = new ObjectDataProvider();
dp.ObjectInstance = new Calculator();
dp.MethodName = "Add";
dp.MethodParameters.Add("10");
dp.MethodParameters.Add("15");
MessageBox.Show(dp.Data.ToString()); // 25

1.10.2 使用 ObjectDataProvider 作为 Binding 的 Source


    
    
    


ObjectDataProvider dp = new ObjectDataProvider();
dp.ObjectInstance = new Calculator();
dp.MethodName = "Add";
dp.MethodParameters.Add("0");
dp.MethodParameters.Add("0");

Binding bindingToArg1 = new Binding("MethodParameters[0]")
{
    Source = dp,
    BindsDirectlyToSource = true,//告诉Binding对象只负责把从UI得到的数据写入Source(odp)而不是写入odp对象包装的Calculator对象中,默认 false
    UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
};

Binding bindingToArg2 = new Binding("MethodParameters[1]")
{
    Source = dp,
    BindsDirectlyToSource = true,
    UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
};

Binding bindingToResult = new Binding(".") { Source = dp };

this.textBlockArg1.SetBinding(TextBox.TextProperty, bindingToArg1);
this.textBlockArg2.SetBinding(TextBox.TextProperty, bindingToArg2);
this.textBlockResult.SetBinding(TextBox.TextProperty, bindingToResult);

1.11 使用 Binding 的 RelativeSource


    
        
            
                
                    
                    
                    
                    
                    
                    
                    
                    
                
            
        
    

RelativeSource rs = new RelativeSource();
rs.AncestorLevel = 1;
rs.AncestorType = typeof(StackPanel);
Binding binding = new Binding("Name") { RelativeSource = rs };

this.textBlock1.SetBinding(TextBox.TextProperty, binding);

RelativeSource rs2 = new RelativeSource();
rs2.AncestorLevel = 2;
rs2.AncestorType = typeof(StackPanel);
Binding binding2 = new Binding("Name") { RelativeSource = rs2 };

this.textBlock2.SetBinding(TextBox.TextProperty, binding2);

RelativeSource rs3 = new RelativeSource();
rs3.AncestorLevel = 3;
rs3.AncestorType = typeof(Grid);
Binding binding3 = new Binding("Name") { RelativeSource = rs3 };

this.textBlock3.SetBinding(TextBox.TextProperty, binding3);

RelativeSource rs4 = new RelativeSource();
rs4.Mode = RelativeSourceMode.Self;
Binding binding4 = new Binding("Name") { RelativeSource = rs4};

this.textBlock4.SetBinding(TextBox.TextProperty, binding4);

// s1
// s2
// g3
// textblock4
// s1
// s2
// g3
// textblock8

从 textBlock3.Text 展示的是 "g3",可以看出 RelativeSource.AncestorLevel 表示从自身开始,往根结点方向找父节点,找第 x 个 AncestorType 的元素;
如果是找自身,就用 RelativeSource.Mode = RelativeSourceMode.Self;
RelativeSource 有三个静态属性:PreviousData、Self、TemplateParent,分别对应 RelativeSourceMode 的三个同名称的枚举值,在 DataTemplate 中常用到,通过 ILSpy 可以看到源代码:

public static RelativeSource TemplatedParent
{
    get
    {
        if (s_templatedParent == null)
        {
            s_templatedParent = new RelativeSource(RelativeSourceMode.TemplatedParent);
        }
        return s_templatedParent;
    }
}

原文:https://www.cnblogs.com/MichaelLoveSna/p/14441742.html

文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐