Databinding绑定不同上下文的属性

The Rhine–Meuse–Scheldt river delta in the Netherlands

绑定某父级的属性

假设场景:

存在一个已经设置了Item source的ListView,ListView的子项里有一个按钮,点击按钮,触发事件。

直接在子项属性上bind,只能读取到Item source的对象的对应属性,不能读取到全局DataContext的属性,要做到读取Datacontext,则需要设置RelativeSource来确认上下文。

例子:

<ListView
	Grid.Column="1" Grid.Row="1"
	ItemsSource="{Binding IdCardInfos}">
	<ListView.ItemTemplate>
		<DataTemplate>
			<wpfui:Button Icon="Delete12" Margin="15,0,0,0" FontSize="20" 
									  Command="{Binding Path=DataContext.DeleteIdCardCommand, RelativeSource={RelativeSource AncestorType=ListView}}" 
									  CommandParameter="{Binding}"/>
		</DataTemplate>
	</ListView.ItemTemplate>
</ListView>
  1. 在这里,使用RelativeSource={RelativeSource AncestorType=ListView}}" 约定绑定的属性DataContext为父级的Listview,之后绑定时读取的DataContext.DeleteIdCardCommand就是ListView的DataContext.DeleteIdCardCommand,当然如果要读取其他Listview的属性也可以直接绑定。

  2. 可以使用RelativeSource="{RelativeSource self}"来绑定UI对象自己的属性。

  3. 直接只有Binding则代表当前的DataContext自身,为数据项,而非UI对象。

绑定Command

可以通过如上所示的方式绑定command并传递参数,在这里复述一下:

<wpfui:Button Icon="Delete12" Margin="15,0,0,0" FontSize="20" 
	  Command="{Binding Path=DataContext.DeleteIdCardCommand, RelativeSource={RelativeSource AncestorType=ListView}}" 
	  CommandParameter="{Binding}"/>

参数是可选的,有的话只能有一个。

如果要传递多个参数,可以自定义Converter来实现

自定义多参数绑定Converter

首先定义一个类,实现Converter基础功能:

using System;
using System.Globalization;
using System.Windows.Data;

namespace WPFBase.Base.BindingConverter
{
    public class MultiBindingConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            return values.Clone();
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            return (object[])value;
        }
    }
}

在要使用的xaml中声明它:

xmlns:bindingconverter="clr-namespace:WPFBase.Base.BindingConverter;assembly=WPFBase"

<Page.Resources>
	<bindingconverter:MultiBindingConverter x:Key="MultiBindingConverter"/>
</Page.Resources>

在对应要绑定的地方使用它:

<wpfui:ToggleSwitch HorizontalAlignment="Center" Command="{Binding DataContext.OrderIDCardChangeCommand, RelativeSource={RelativeSource AncestorType=ListView}}">
	<wpfui:ToggleSwitch.CommandParameter>
		<MultiBinding Converter="{StaticResource MultiBindingConverter}">
			<Binding Path="."/>
			<Binding Path="IsChecked" RelativeSource="{RelativeSource self}"/>
		</MultiBinding>
		<!--<model:IDCardInfoToggle Info="{Binding DataContext}" IsSeleted="{Binding Path=IsEnabled, RelativeSource={RelativeSource AncestorType=wpfui:ToggleSwitch}}"/>-->
	</wpfui:ToggleSwitch.CommandParameter>
</wpfui:ToggleSwitch>

其中,<Binding Path="."/> 代表了绑定到自身的数据源上,类似于直接在属性中binding,<Binding Path="IsChecked" RelativeSource="{RelativeSource self}"/>则是将上下文指定到了UI控件自身,Path获取的就是UI控件自身的属性。

在View Model中定义Command:

[ObservableProperty]
public ICommand MyCommand;

// 初始化它
OrderIDCardChangeCommand = new RelayCommand<object>(item => MyCommandMethod(item!));

private void MyCommandMethod(object parameter)
{
	var obj = (object[])parameter;
	// 在这里可以获取到数据,按照bind的时候的顺序,取数组的值即可
}