WPF 数据绑定

DataContext

  WPF控件均有DataContext属性,可把DataContext理解为控件的数据源。

      Binding给人的错觉是当前控件没有设置DataContext属性时会自动向UI元素树一路向树的根部找过去,直到找到已设置DataContext属性的控件,并把此控件的DataContext作为自身的DataContext,Binding并没有这么智能。因为DataContext是依赖属性,当没有为控件的依赖属性显示赋值值,控件会把自己的容器控件的属性值当做自己的属性值。实际上是属性值沿着UI元素树向下传递了。

  有两种方式设置控件的DataContext  

//在Xaml设置

 <Window.DataContext>
    <local:MainViewModel />
 </Window.DataContext>

//或在窗体的.cs文件中设置
 public MainWindow()
 {
        InitializeComponent();
        this.DataContext = new MainViewModel();
  }

Binding声明

展示层和逻辑层的数据沟通通过DataBinding实现。数据绑定由四个部分组成:

绑定目标:目标控件

目标属性:控件中哪个属性要绑定源中某个属性

绑定源:源默认是DataContext

源路径:要绑定源的属性名称

 

<TextBlock Text="{Binding}" />
//等价于
<TextBlock Text="{Binding .}" />
//等价于
<TextBlock Text="{Binding RelativeSource={RelativeSource self}, Path=DataContext}" />
  1. Binding表达式默认第一个参数是Path,所以可以直接把Path去掉

  2. 上述代码行Binding后面什么不写或写一个点表示绑定的是控件本身的DataContext,如果未设置控件绑定的 DataContext 属性,则将检查父控件的 DataContext 属性,依此类推,直到 XAML 对象树的根。如果父元素存在DataContext则该控件自动继承父控件的DataContext。

  3. 要绑定的必须是属性,不能是字段

  4. DataContext实现IPropertyChanged主要是为了当后台属性值发生变化时通知前端,即绑定的源发生变化后通知目标

  5. 默认前端控件输入值后控件失去焦点时会通知源

  6. 控件默认绑定的Source是DataContext

Source

控件中需要指名Source时,Source一般与<XX.Resources> 或资源字典一起使用,还有枚举、静态变量、常量等

<Window.Resources>
     <sys:String  x:Key="str" >Hello World</sys:String>
     <local:MyResource x:Key="myres"/>
  </Window.Resources>
  <StackPanel>
      <TextBlock Text="{Binding Source={StaticResource str}}" />
      <TextBlock Text="{StaticResource str}"/>
      //上面两种方式一样
      <TextBlock Text="{DynamicResource str}"/>
      //当str发生变化时,上面TextBox显示的内容同样变化
      
      <TextBlock Text="{Binding Source={StaticResource myres}, Path=Message}" />
      //静态的变量或枚举使用x:Static绑定
      <TextBlock Text="{Binding Source={x:Static local:MyResource.ConstString}}" />
      <TextBlock Text="{Binding Source={x:Static local:MyResource.StaticString}}" />
      //可简写为:
      <TextBlock Text="{x:Static local:MyResource.ConstString}" />
      <TextBlock Text="{x:Static local:MyResource.StaticString}" />
      
      <TextBlock Text="{Binding Source={x:Static HorizontalAlignment.Center} }"/>      
    </StackPanel>


//后台MyResource类
  public class MyResource
    {
        public string Message { get; set; } = "Public Property";
        public static string StaticString = "StaticString";
        public const string ConstString = "ConstString";
    }

ElementName

ElementName指定的是绑定其他控件的名称,比如某些控件访问不到UI元素树上的控件,可通过x:Reference实现

<TextBox Name="txt" />
<TextBlock Text="{Binding ElementName=txt, Path=Text}" ToolTip="{Binding ElementName=txt, Path=Text}" />
//下面ToolTip找不到txt,在可视化树上发现tooltip没有出现在WIndow上,而是出现在PopupRoot上,
属于弹出来得一个东西,脱离了WIndow
<TextBlock Text="{Binding ElementName=txt, Path=Text}">
   <TextBlock.ToolTip>
      <TextBlock Text="{Binding ElementName=txt, Path=Text}" />
   </TextBlock.ToolTip>
</TextBlock>
//可以通过x:Reference实现,会在Xmal中查找txt
<TextBlock Text="{Binding ElementName=txt, Path=Text}">
   <TextBlock.ToolTip>
      <TextBlock Text="{Binding Source={x:Reference Name=txt}, Path=Text}" />
   </TextBlock.ToolTip>
</TextBlock>
//DataGridTextColumn不是控件,所以也不能通过ElementName实现
<DataGrid>
   <DataGrid.Columns>
       <DataGridTextColumn Header="{Binding Source={x:Reference Name=txt}, Path=Text}" />
   </DataGrid.Columns>
</DataGrid>

RelativeSource

 ======FindAncestor
 //FindAncestor找父级控件,默认是此项
 <StackPanel>
     <TextBlock Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}, Path=Top}" />
 </StackPanel>
 //AncestorLevel默认是离本身最近的控件
 <StackPanel Tag="Level 3">
     <StackPanel Tag="Level 2">
         <StackPanel Tag="Level 1">
              <TextBlock Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=StackPanel, AncestorLevel=2}, Path=Tag}" />
         </StackPanel>
     </StackPanel>
 </StackPanel>
 =========Self
 //绑定控件本身属性的写法
<TextBlock Text="{Binding RelativeSource={RelativeSource Mode=Self}, Path=ActualWidth}" />
等价于
<TextBlock Text="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=ActualWidth}" />


<ListBox>
//每个TextBlock是ListBoxItem的内容
   <TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem}, Path=IsSelected}" />
   <TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem}, Path=IsSelected}" />
   <TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem}, Path=IsSelected}" />
</ListBox>

=====TemplatedParent

<Label Width="300" Height="50" Margin="10" Content="Hello World">
      <Label.Template>
           <ControlTemplate TargetType="Label">
                 <Border Padding="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Margin}">
                      <ContentPresenter />
                 </Border>
             </ControlTemplate>
      </Label.Template>
</Label>
<Label Width="300" Height="50" Margin="10" Content="Hello World">
     <Label.Template>
          <ControlTemplate TargetType="Label">
               <Border>
                    <ContentPresenter Margin="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Padding,Mode=OneWay}" />
                     //等价于下面行
                    <ContentPresenter Margin="{TemplateBinding Padding}" />
               </Border>
         </ControlTemplate>
     </Label.Template>
</Label>

StringFormat

<Grid>
    <StackPanel>
    //显示窗体Top属性值  102
        <TextBlock Text="{Binding ElementName=window, Path=Top}" />
     //按照特定格式显示窗体top属性值 Top:102.231
        <TextBlock Text="{Binding ElementName=window, Path=Top, StringFormat='Top:{0:F3}'}" />
        <TextBlock Text="{Binding ElementName=window, Path=Left, StringFormat='Left:{0:F3}'}" />
     //多个绑定 Pos:102.231 202.222
       <TextBlock>
            <TextBlock.Text>
                 <MultiBinding StringFormat="Pos:{0} {1}">
                        <Binding ElementName="window" Path="Top" />
                        <Binding ElementName="window" Path="Left" />
                 </MultiBinding>
            </TextBlock.Text>
       </TextBlock> 
      //label使用ContentStringFormat约定格式
       <Label Content="{Binding ElementName=window, Path=Top}" ContentStringFormat="Top:{0:F3}" />
       <Label Content="{Binding ElementName=window, Path=Left}" ContentStringFormat="Left:{0:F3}" />
    </StackPanel>
</Grid>

TargetNullValue和*FallbackValue*

//当Message为空时,显示的文本是Empty
<TextBlock Text="{Binding Message, TargetNullValue=Empty}" />
//当Hello属性没有时或绑定错误时显示Empty 针对无法绑定(给定的Path不存在)时使用的默认值,
<TextBlock Text="{Binding Hello, FallbackValue=Empty}" />

在B站上看完一些视频后记录的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值