(4)WPF深入解析绑定

1、WPF绑定

1.1、简介

  WPF绑定使得原本需要多行代码实现的功能,现在只需要简单的XAML代码就可以完成之前多行后台代码实现的功能。
  WPF绑定可以理解为一种关系,该关系告诉WPF从一个源对象提取一些信息,并将这些信息来设置目标对象目标属性
  目标属性总是依赖属性。但源对象可以是任何内容,可以是一个WPF元素、或ADO.NET数据对象自定义的数据对象等。

1.2、三种常见用绑定方式

1)Source绑定

  最简单的绑定方法,常用来绑定图片、资源字典的源对象。

<Image Source="../Image/zhenghe_uideal_mr_plaque_narrow.png" Stretch="Fill" Height="32" Width="30" HorizontalAlignment="Left" />
<ResourceDictionary Source="/UIH.Mcsf.CommonControlTheme;component/CommonControl/Public.xaml" />

2)绑定元素对象的实现

  绑定元素对象的数据源,是一个WPF元素对象的依赖属性。由于依赖属性具有内置的更改通知支持,因此,当在源对象中改变依赖属性的值时,会立即更新目标对象中的绑定属性。
  下面通过一个简单的例子来演示下如何绑定元素对象。具体的XAML代码(这里不需要后台代码)如下所示:

 <StackPanel>
        <Slider Name="sliderFontSize" Margin="3"
            Minimum="1" Maximum="40" Value="10" TickFrequency="1" TickPlacement="TopLeft"/>
        <TextBlock Margin="10" Text="LearningHard" Name="lbtext"
                   FontSize="{Binding ElementName=sliderFontSize, Path=Value}"></TextBlock>
    </StackPanel>

  在上面XAML代码中,TextBlock的FontSize属性绑定时,使用ElementName指定源元素对象名,Path指定源元素的依赖属性。
  TextBlock控件的FontSize属性绑定了Slider控件的Value属性,由于源属性Value是依赖属性,具体内置的更改通知功能,所以Slider控件Value值的改变,直接影响TextBlock控件FontSize的值。运行结果如下,当移动上图中Slider控件上的游标时,下面的文本字体大小也会跟着一起改变:


                                                 

3)DataContext绑定方式

  • 数据驱动的应用程序中,更常见DataContext绑定方式的情况。
  • 绑定的信息必须存储在一个公有属性中。因为WPF绑定不能获取私有信息或公有字段。
  • 绑定表达式中的RelativeSource属性,可以指定绑定源对象相对位置;
  • 如果元素没有DataContext,也没有用RelativeSource指定源对象的相对位置,那么WPF会从当前元素开始在元素树中向上查找,使用第一个非空的DataContext属性
    可以省去重复在多个控件中设置相同的DataContext属性)。

  下面演示如何使用DataContext属性来绑定一个自定义对象的属性。
  首先自定义一个实现了INotifyPropertyChanged接口的类。这个接口是为了发出属性更改的通知,当源对象的公共属性发生改变时,该属性的值会立即响应到界面上显式。具体的实现代码如下所示:

 

   运行结果如下:

 

1.3、绑定模式(BindingMode)

  1. OneWay:源属性变就更新目标属性。
  2. TwoWay:源属性变就更新目标,并且目标属性变就更新源属性。
  3. OneTime:只根据源属性来设置目标属性,以后都不会变。
  4. OneWayToSource:与OneWay相反,目标属性变就更新源属性。
  5. Default:可以单向或双向,是靠被指定的源属性或目标属性是否有get或set来指定的。 

1.4、绑定更新(UpdateSourceTrigger

  通过指定Binding.UpdateSourceTrigger属性,设置在目标属性变化时,源属性的更新时机(因此只针对TwoWay和OneWayToSource绑定模式)。

  UpdateSourceTrigger有以下4种类型:

 

 

   对于UpdateSourceTrigger.Explicit模式。此时就需要额外编写代码手动触发更新,此时可以添加一个Apply按钮,并在按钮的Click事件处理程序中调用BindingExpression.UpdateSource方法触发立即刷新并更新字体大小的操作。具体的实现代码如下所示:

//获得应用于文本框上的绑定
BindingExpression be = txtFontSize.GetBindingExpression(TextBox.TextProperty);
//调用UpdateSource更新源对象
be.UpdateSource();                                                                                                                                             

1.5、RelativeSource

  在WPF绑定的时候,可以使用RelativeSource,指当前元素和绑定源的位置关系。

1)控件关联自身的属性——Self

<Window x:Class="RelativeSource.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>
        <StackPanel>
            <TextBox Height="30" Width="60" Name="Box1" Text="{Binding RelativeSource={RelativeSource Mode=self},Path=Name }"/>
        </StackPanel>
    </Grid>
</Window>

2)控件关联其父级容器的属性——AncestorType

  下面是AncestorType的例子,其中:

  • AncestorLevel,它指的是以Bingding目标控件为起点的层级偏移量,S1的偏移量是1,G2的偏移量是2,G1是偏移量3,
  • AncestorType指的是要找的目标对象的类型。

  值得注意的是AncestorLevel必须参考AncestorType使用,如下设置了AncestorType={x:Type Grid},则Bingding在寻找时会忽略非Grid的控件,此时G2的偏移量是1,G1的偏移量是2,StackPanel被忽略。

<Window x:Class="RelativeSource.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="G1">
        <Grid Name="G2">
            <StackPanel Name="S1">
                <TextBox Height="30" Width="60" Name="Box1" Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Grid}, AncestorLevel=2},Path=Name }"/>
            </StackPanel>
        </Grid>
    </Grid>
</Window>

2)控件关联模板的属性——TemplatedParent

  TemplatedParent用于控件模板(ControlTemplate)绑定,会指定源属性是模板使用者,可以使用以下两种方式指定:

Background="{Binding Foreground, RelativeSource={RelativeSource TemplatedParent}}"
Background="{TemplateBinding Foreground}"

  使用TemplateBinding有以下不同

  • Binding的一个轻量级版本  
  • 数据绑定是单向的,从数据源到目标。
  • 数据对象进行自动转换,数据源和目标的数据类型不同时候,需要自己写转换器。
<Window.Resources>
    <Style TargetType="{x:Type Button}">
        <Setter Property="Background" Value="Green"/>
            <Setter Property="Template">              
                <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Grid>
                        <Ellipse>
                            <Ellipse.Fill>
                                <SolidColorBrush Color="{Binding Path=Background.Color,RelativeSource={RelativeSource TemplatedParent}}"/>
                            </Ellipse.Fill>
                        </Ellipse>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>

4、提高列表性能

   对于列表控件,如果绑定的数据源具有大量记录时,可能会出现性能问题,对此,WPF做了以下两种方式种方法:

  • 初始化性能提升:UI虚拟化
  • 滚动性能提升:项目容器再循环和延迟滚动

1)UI虚拟化

  列表仅为当前显示的项创建容器对象的一种技术,例如,如果有一个具有5万条记录的列表,但是可见区域只能包含30条记录,ListBox控件只创建30个ListBoxItem对象。
  WPF中UI虚拟化是通过VirtualizingStackPanel容器实现的。像ListBox、ListView和DataGrid都自动使用VirtualizingStackPanel面板布局它们的子元素,所以,这些控件都默认支持虚拟化功能。然而,ComboBox需要支持虚拟化支持,必须明确提供新的ItemPanelTemplate添加虚拟化支持,具体实现如下所示:

<ComboBox>
   <ComboBox.ItemsPanel>
       <ItemsPanelTemplate>
           <VirtualizingStackPanel></VirtualizingStackPanel>
       </ItemsPanelTemplate>
   </ComboBox.ItemsPanel>
</ComboBox>

TreeView控件也支持虚拟化,但它在默认情况下,关闭了该支持,你需要显式启用该特性,具体使用的启用代码如下所示:

 <TreeView VirtualizingPanel.IsVirtualizing="True" />

2)项目容器再循环

  WPF 3.5 SP1使用项目容器再循环改进了虚拟化。但是如果启用了项目容器再循环,ListBox控件会保存少量ListBoxItem对象存活,当滚动时,将新数据加到这些之前的ListBoxItem对象,从而重复使用它们。
  项目容器再循环提供了滚动性能,并降低了内存消耗量。为了确保向后兼容,除了DataGrid之后的所有列表控件默认都禁用该特性,如需支持,需要显式启用。

<ListBox VirtualizingPanel.VirtualizationMode="Recycling"/>

3)延迟滚动

  为了进一步提供滚动性能,可以开启延迟滚动功能。使用延迟滚动,当用户在滚动条上拖动滚动滑块时不更新列表显示,只有用户释放了滚动滑块时才刷新。
  但当用户需要在滚动时查看目前滚动位置,则就可以不启用该特性。
  如需支持,也需要显式启用。

<ListBox ScrollViewer.IsDeferredScrollingEnabled="True"/>

 

摘自

https://www.cnblogs.com/zhili/tag/WPF/

posted @ 2020-08-10 19:44  代码吸血虫  阅读(487)  评论(0)    收藏  举报