• 【wpf】深度解析,Bingding是如何寻找数据源的 上篇


    数据源存放位置

    目前我用存放数据源的属性有:

    • Resources
    • ItemsSource
    • DataContext

    一般控件都有Resources和DataContext属性,列表控件会多一个ItemsSource。

     Resources可以放多个资源,但是需要给每一个资源指定一个key。

    1. <Page.Resources>
    2. <local:TestMode2 x:Key="TM2"/>
    3. <local:TestMode x:Key="TM1"/>
    4. Page.Resources>

    而 ItemsSourceDataContext只能放一个对象(不需要指定key)

    1. <Page.DataContext>
    2. <local:TestMode2/>
    3. Page.DataContext>

    Bingding  表达式

    Bingding  表达式 有一些常用的方法:

    • Source  
    • RelativeSource 
    • Path

    Path  相当于是一个过滤器,用来选择具体是哪一个属性

    Source  是指定资源的位置,Source  指定的资源是去Resources中找,寻找资源时直接指定key,就能一步到位。

    <TextBlock Text="{Binding Source={StaticResource TM2 }, Path=TestDate }"/>

    但如果,我们在绑定表达式中,不写Source  指定资源时,绑定表达式就会自动到ItemsSourceDataContext 中去找。

    <TextBlock Text="{Binding Path=Value}"/>

    而且,默认的寻找方式是一层层的往上找,如果在某一层找到ItemsSourceDataContext  被设置过,不管Path指定的属性是否存在,就会停止继续往上找。

    那么是否改变这种默认的查找方式呢?答案是使用RelativeSource 

    你会发现 RelativeSource 和 Source  有着本质的区别, 它并不是指定源的位置,而是用于改变默认的寻找资料的方式。(因为此时 源的位置是不确定的,是需要按照一定的规则去寻找的 

    1. <TextBlock Text="{Binding Path=DataContext.DM1.Value, 
    2.                             RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Page}}"/>

    感悟

    在使用数据绑定时,我们更喜欢,使用不指定Source 的方式,此时会自动去ItemsSourceDataContext  中寻找,这种方式更加的灵活。

    RelativeSource

    接下来,我将介绍 RelativeSource 是如何改变默认的寻找资源的方式。并显示实际的例子。

    先看一下它的具体写法

    1. <TextBlock  Background="Orange" Text="{Binding Path=DataContext.DM1.Value, 
    2.                             RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Page}}"/>

    最主要就是这个Mode,它定义了寻找源的几种规则:

    1. //
    2. // 摘要:
    3. // Describes the location of the binding source relative to the position of the
    4. // binding target.
    5. public enum RelativeSourceMode
    6. {
    7. //
    8. // 摘要:
    9. // Allows you to bind the previous data item (not that control that contains the
    10. // data item) in the list of data items being displayed.
    11. PreviousData = 0,
    12. //
    13. // 摘要:
    14. // Refers to the element to which the template (in which the data-bound element
    15. // exists) is applied. This is similar to setting a System.Windows.TemplateBindingExtension
    16. // and is only applicable if the System.Windows.Data.Binding is within a template.
    17. TemplatedParent = 1,
    18. //
    19. // 摘要:
    20. // Refers to the element on which you are setting the binding and allows you to
    21. // bind one property of that element to another property on the same element.
    22. Self = 2,
    23. //
    24. // 摘要:
    25. // Refers to the ancestor in the parent chain of the data-bound element. You can
    26. // use this to bind to an ancestor of a specific type or its subclasses. This is
    27. // the mode you use if you want to specify System.Windows.Data.RelativeSource.AncestorType
    28. // and/or System.Windows.Data.RelativeSource.AncestorLevel.
    29. FindAncestor = 3
    30. }

    FindAncestor

    表示找到最顶层,一般配合AncestorType使用,AncestorType指定一种类型,表示遇到这种类型就停止寻找。

    Self 

    表示Bingding的属性就在自身寻找。

    TemplatedParent 

    这个就是模板匹配中常用到的TemplatBinding

    PreviousData 

    这个是表示绑定上一个子项,目前感觉只能在数据模板中才会生效。


    以下是具体的代码部分:

    1. <Page x:Class="WpfTest.绑定源的寻找"
    2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    4. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    5. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    6. xmlns:local="clr-namespace:WpfTest"
    7. mc:Ignorable="d"
    8. d:DesignHeight="450" d:DesignWidth="800" Background="AliceBlue"
    9. Title="绑定源的寻找">
    10. <Page.Resources>
    11. <local:TestMode2 x:Key="TM2"/>
    12. <local:TestMode x:Key="TM1"/>
    13. Page.Resources>
    14. <Page.DataContext>
    15. <local:TestMode2/>
    16. Page.DataContext>
    17. <UniformGrid Rows="3">
    18. <ItemsControl ItemsSource="{Binding Path=ValueList}">
    19. <ItemsControl.ItemTemplate>
    20. <DataTemplate>
    21. <UniformGrid Columns="4" Rows="4">
    22. <TextBlock Text="{Binding Path=Value}"/>
    23. <TextBlock Background="Orange" Text="{Binding Path=DataContext.DM1.Value,
    24. RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Page}}"/>
    25. <TextBlock Background="Green" Text="{Binding Path=DataContext.TestDate,
    26. RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Page}}"/>
    27. <TextBlock Text="{Binding }"/>
    28. <TextBlock Text="{Binding Source={StaticResource TM2 }, Path=TestDate }"/>
    29. UniformGrid>
    30. DataTemplate>
    31. ItemsControl.ItemTemplate>
    32. ItemsControl>
    33. <StackPanel>
    34. <TextBlock Background="Orange" Text="{Binding Path=DataContext.DM1.Value,
    35. RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Page}}"/>
    36. <TextBlock Background="Green" Text="{Binding Path=ActualWidth,
    37. RelativeSource={RelativeSource Mode=Self}}"/>
    38. <ItemsControl ItemsSource="{Binding Path=ValueList}">
    39. <ItemsControl.ItemTemplate>
    40. <DataTemplate>
    41. <StackPanel Orientation="Horizontal">
    42. <TextBlock Text="{Binding Value}"/>
    43. <TextBlock Text="{Binding Path=Value,
    44. RelativeSource={RelativeSource Mode=PreviousData}}" Foreground="Red" Margin="10,0,0,0"/>
    45. StackPanel>
    46. DataTemplate>
    47. ItemsControl.ItemTemplate>
    48. ItemsControl>
    49. StackPanel>
    50. UniformGrid>
    51. Page>
    1. using System;
    2. using System.Collections.Generic;
    3. using System.ComponentModel;
    4. using System.Linq;
    5. using System.Text;
    6. using System.Threading.Tasks;
    7. using System.Windows;
    8. namespace WpfTest
    9. {
    10. public class TestMode2
    11. {
    12. public string TestDate { get; set; } = "test";
    13. public DataModel1 DM1 { get; set; } = new DataModel1();
    14. public DataModel2 DM2 { get; set; } = new DataModel2();
    15. public class DataModel1 : INotifyPropertyChanged
    16. {
    17. private int _value = 1;
    18. public int Value
    19. {
    20. get { return _value; }
    21. set
    22. {
    23. _value = value;
    24. PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Value"));
    25. }
    26. }
    27. public event PropertyChangedEventHandler PropertyChanged;
    28. }
    29. public class DataModel2 : INotifyPropertyChanged
    30. {
    31. private int _value = 2;
    32. public int Value
    33. {
    34. get { return _value; }
    35. set
    36. {
    37. _value = value;
    38. PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Value"));
    39. }
    40. }
    41. public event PropertyChangedEventHandler PropertyChanged;
    42. public int MyProperty { get; set; } = 3;
    43. }
    44. public List ValueList { get; set; } = new List()
    45. {
    46. new DataModel2{ Value=1},
    47. new DataModel2{ Value=2},
    48. new DataModel2{ Value=3},
    49. new DataModel2{ Value=4},
    50. };
    51. }
    52. }

  • 相关阅读:
    MFC 中创建并显示二维码
    C++:多态、多态的实现及优点、虚函数(纯虚函数)
    Azure Blob MD5算法
    mobx实战,几分钟入门
    〔003〕虚幻 UE5 基础教程和蓝图入门
    LeetCode Cookbook 树(2)
    热烈祝贺埃文科技代码特工队斩获2023黄河鲲鹏开发者大赛河南赛区创新赛道二等奖
    java计算机毕业设计Vue和mysql智能图书管理系统MyBatis+系统+LW文档+源码+调试部署
    STM32智能物流机器人系统教程
    踩坑ffmpeg录制的mp4无法在浏览器上播放
  • 原文地址:https://blog.csdn.net/songhuangong123/article/details/126195727