WPF DataBinding some other details

1. RelativeSource
      用来指定一个相对的source位置,通常有以下三种方式:

(1): RelativeSource.Self
       允许把自己当作相对的元素。
(2): RelativeSource.FindAncestor
       根据指定的类型(AncestorType)和向上寻找的层次(AncestorLevel)向祖先寻找。例如AncestorLevel
设为1,则把第一次找到的匹配的object作为参照对象,如果为2,则把第二次匹配的object作为参照对象。
<StackPanel Background="Blue">
   <TextBlock Background="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType= {x:Type  StackPanel},    AncestorLevel=1}, Path=Background}" />
</StackPanel>

(3): RelativeSource.TemplatedParent
      当自己在一个template里面的时候,取被设置了该template的对象作为参照对象。

<Window>
<Window.Resources>
   <ControlTemplate x:Key="myButtonTemplate" TargetType="{x:Type Button}">
      <StackPanel Background="{Binding RelativeSource={RelativeSource
TemplatedParent},Path=Background}"/>
   </ControlTemplate>
</Window.Resources>
<Button Template="{StaticResource myButtonTemplate}" Background="Blue"/>
</Window>

在这里,设置了ButtonBackground是什么,则template里的StackPanelBackground就是什么了。
2. TemplateBindingContentPresenter
    Binding提供了更灵活的绑定方式,但是开销较大。TemplateBinding只可以在以下一种场景使用,
但是很方便:当一个元素在一个template里面的时候,用TemplateBinding将该元素的某一个属性和
templat的元素的某一个属性绑定,这样被template的元素的这个属性值就会传给这个元素。
例如下面的例子:

<Window x:Class="CommonQuestions.Window1
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     Title="CommonQuestions" Height="300 Width="300
     >
        <Window.Resources>
            <ControlTemplate TargetType="{x:Type Button}" x:Key="buttonTemplate">
                <Border BorderBrush="{TemplateBinding Property=Background}" 
BorderThickness="3 >
                    <ContentPresenter Margin="10/>
                </Border>
            </ControlTemplate>
        </Window.Resources>
        <StackPanel Margin="20>
            <Button Template="{StaticResource buttonTemplate}" 
HorizontalAlignment="Center" Background="SteelBlue">Hello</Button>
        </StackPanel>
    </Window>

在这里,ButtonBackground"SteelBlue"就会传递给它所应用的ControlTemplate里的Border
BorderBrush属性了。TemplateBinding是可以和BindingRelativeSource.TemplatedParent转换的,
作用一样。上面的也可以写成:
<Border BorderBrush="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=Background}"/>
注意这里只能是OneWay的传递方式,要实现其它的传递方式,
就必须用Binding了。另外,TemplateBinding也提供了ConverterConverterParameter,满足在
不同类型间传递了。
ContentPresenter
ContentPresenter是一个用在ContentControltemplate里的元素,ContentPresenter is used to
specify where the content should go in the ContentControl's template(也就是说用它指定
应用这个templateControlContent显示在template里的哪个位置)。
例如上例中所用到的<ContentPresenter Margin="10/>实际上等价于下面的语句:

<ContentPresenter Content="{TemplateBinding Content}" ContentTemplate=
"{TemplateBinding ContentTemplate}" ContentTemplateSelector="{TemplateBinding
ContentTemplateSelector}" Margin="10/>

因为对于这里的ContentContentTemplate的声明是任何时候都有的情况,所以我们省略
成了上面的形式。但是这里说明了我们可以显式的另外指定ContentPresenter Content
如果我们改成:

<ContentPresenter Content="{TemplateBinding Background}" Margin="10/>

以前是把"Hello"显示在templateBorder里,现在显示的却是"#FF4682B4,也就是说被
新设的值覆盖了。

3. IValueConverter
ConvertBack里的实现,如果return Binding.DoNothing,例如:
public object ConvertBack(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
    {
if(...)
        return Binding.DoNothing;
return ....;
    }

如果return Binding.DoNothing,则In a one-way binding, the data goes from
Source -> Converter -> Target. If you return Binding.DoNothing in
the Convert method, the data transfer goes from Source -> Converter
and stops there, it does not continue to the target. Future changes
in the Source will still trigger a
data transfer,也就是说这次数据传递被取消,但是以后的传递如果不出错,还是
会继续传递的。如果return null,则当null是合法的source值时,会赋给source
但不合法时会报错。因为在OneWay binding时,ConvertBack是不会执行的,所以这里
最好是throw一个Exception,如果有错误执行到这里了,程序会报错,我们也容易发现错误了。

4. ItemsPanelTemplate
对于ItemsControl,用ItemsPanelTemplate指定它的所有ItemsLayout,例如
Items水平或竖直排列,对齐方式等等。
例如下面的例子创建一个所有Items以水平方向排列的ListBox
<Style TargetType="ListBox">
  <Setter Property="ItemsPanel">
    <Setter.Value>
      <ItemsPanelTemplate>
        <StackPanel Orientation="Horizontal"
                    VerticalAlignment="Center"
                    HorizontalAlignment="Center"/>
      </ItemsPanelTemplate>
    </Setter.Value>
  </Setter>
</Style>
这里用到了ItemsPanel属性。

下面的方式不设置ItemsPanel属性,而是通过更改ListBoxControlTemplate
创建了一个带有rounded corners的水平排列的ListBox
<Style TargetType="ListBox">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="ListBox">
        <Border CornerRadius="5" Background="{TemplateBinding ListBox.Background}">
          <ScrollViewer HorizontalScrollBarVisibility="Auto">
            <StackPanel Orientation="Horizontal"
                       VerticalAlignment="Center"
                       HorizontalAlignment="Center"
                       IsItemsHost="True"/>
          </ScrollViewer>
        </Border>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>
但是这种方式注意的是要设置StackPanelIsItemsHost属性为true
然而,我们可以在ControlTemplate中使用ItemsPresenter,让它调用
ItemsPanelTemplatelayout所有的Items
<Style TargetType="{x:Type ListBox}">
  <Setter Property="ItemsPanel">
    <Setter.Value>
      <ItemsPanelTemplate>
        <StackPanel Orientation="Horizontal"
                     VerticalAlignment="Center"
                     HorizontalAlignment="Center"/>
      </ItemsPanelTemplate>
    </Setter.Value>
  </Setter>
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type ListBox}">
        <Border CornerRadius="5"
                Background="{TemplateBinding ListBox.Background}">
          <ScrollViewer HorizontalScrollBarVisibility="Auto">
            <ItemsPresenter/>
          </ScrollViewer>
        </Border>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

又如下面的例子,
<!--Define a control template for a HeaderedItemsControl-->
<Style TargetType="HeaderedItemsControl">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type HeaderedItemsControl}">
        <StackPanel>
          <Grid>
            <Rectangle Fill="{TemplateBinding Background}"/>
            <ContentPresenter ContentSource="Header"/>
          </Grid>
          <Grid>
            <Rectangle Stroke="{TemplateBinding BorderBrush}"/>
            <ItemsPresenter Margin="2,0,0,0"/>
          </Grid>
        </StackPanel>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

<HeaderedItemsControl  xmlns:sys="clr-namespace:System;
                       assembly=mscorlib"
                       Header="My colors"
                       Background="SteelBlue"
                       BorderBrush="DarkSlateBlue">
  <sys:String>Red</sys:String>
  <sys:String>Yellow</sys:String>
  <sys:String>Blue</sys:String>
  <sys:String>Green</sys:String>
</HeaderedItemsControl>
注意这里用ContentPresenterContentSource属性指定了将被template
的元素的Header属性显示在第一个Rectangle内。后面的ItemsPresenter
属性指定了在这个Rectangle内显示所有Items,并且所有的ItemsMargin
2000

5. BindingNotifyOnSourceUpdatedNotifyOnTargetUpdated属性
例如NotifyOnTargetUpdated就指示是否触发TargetUpdated事件当数据从sourcetarget传递的时候。默认是false,例如:

<TextBlock Grid.Row="1" Grid.Column="1" Name="RentText"
  Text="{Binding Path=Rent, Mode=OneWay, NotifyOnTargetUpdated=True}"
  TargetUpdated="OnTargetUpdated"/>

public void OnTargetUpdated(Object sender, DataTransferEventArgs args)
{
  // Handle event
}

NotifyOnSourceUpdated则是相反方向传递的情况。

6.注意x:Static的用法

The code entity referenced must be one of the following:

  • constant
  • static property
  • field
  • enumeration value

例如:

<Button FontSize="8" Margin="10, 10, 5, 5" Grid.Column="0" Grid.Row="5"

HorizontalAlignment="Left"

Height="{x:Static SystemParameters.CaptionHeight}"

Width="{x:Static SystemParameters.IconGridWidth}">

SystemParameters

</Button>

7. Binding Path的几种特殊写法

  • To bind to an attached property, place parentheses around the attached property. For example, to bind to the attached property DockPanel.Dock, the syntax is Path=(DockPanel.Dock).
  • When the source is a collection view, the current item can be specified with a slash (/). For example, the clause Path=/ sets the binding to the current item in the view. When the source is a collection, this syntax specifies the current item of the default collection view.
  • Property names and slashes can be combined to traverse properties that are collections. For example, Path=/Offices/ManagerName specifies the current item of the source collection, which contains an Offices property that is also a collection. Its current item is an object that contains a ManagerName property.
  • Optionally, a period (.) path can be used to bind to the current source. For example, Text="{Binding}" is equivalent to Text="{Binding Path=.}".
原文地址:https://www.cnblogs.com/bear831204/p/1310987.html