WP中系统没有像WPF中直接支持MultiBinding,可以通过以下代码实现
public class BindingCollection : Collection<BindingBase>
{
// Fields
private readonly BindingCollectionChangedCallback _collectionChangedCallback;
// Methods
//internal BindingCollection(BindingCollectionChangedCallback callback)
//{
// _collectionChangedCallback = callback;
//}
protected override void ClearItems()
{
base.ClearItems();
OnBindingCollectionChanged();
}
protected override void InsertItem(int index, BindingBase item)
{
if (item == null)
{
throw new ArgumentNullException("item");
}
ValidateItem(item);
base.InsertItem(index, item);
OnBindingCollectionChanged();
}
private void OnBindingCollectionChanged()
{
if (_collectionChangedCallback != null)
{
_collectionChangedCallback();
}
}
protected override void RemoveItem(int index)
{
base.RemoveItem(index);
OnBindingCollectionChanged();
}
protected override void SetItem(int index, BindingBase item)
{
if (item == null)
{
throw new ArgumentNullException("item");
}
ValidateItem(item);
base.SetItem(index, item);
OnBindingCollectionChanged();
}
private static void ValidateItem(BindingBase binding)
{
if (!(binding is Binding))
{
throw new NotSupportedException("BindingCollectionContainsNonBinding");
}
}
}
/// <summary>
/// A simple element with a single Value property, used as a ‘slave‘
/// for a Binding.
/// </summary>
public class BindingSlave : FrameworkElement, INotifyPropertyChanged
{
#region Value
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(object), typeof(BindingSlave),
new PropertyMetadata(null, OnValueChanged));
public object Value
{
get { return GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
private static void OnValueChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
{
BindingSlave slave = depObj as BindingSlave;
Debug.Assert(slave != null);
slave.OnPropertyChanged("Value");
}
#endregion
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
#endregion
}
/// <summary>
/// Provides a mechanism for attaching a MultiBinding to an element
/// </summary>
public class BindingUtil
{
#region DataContextPiggyBack attached property
/// <summary>
/// DataContextPiggyBack Attached Dependency Property, used as a mechanism for exposing
/// DataContext changed events
/// </summary>
public static readonly DependencyProperty DataContextPiggyBackProperty =
DependencyProperty.RegisterAttached("DataContextPiggyBack", typeof (object), typeof (BindingUtil),
new PropertyMetadata(null, new PropertyChangedCallback(OnDataContextPiggyBackChanged)));
public static object GetDataContextPiggyBack(DependencyObject d)
{
return (object) d.GetValue(DataContextPiggyBackProperty);
}
public static void SetDataContextPiggyBack(DependencyObject d, object value)
{
d.SetValue(DataContextPiggyBackProperty, value);
}
/// <summary>
/// Handles changes to the DataContextPiggyBack property.
/// </summary>
private static void OnDataContextPiggyBackChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
FrameworkElement targetElement = d as FrameworkElement;
// whenever the targeElement DataContext is changed, copy the updated property
// value to our MultiBinding.
MultiBindings relay = GetMultiBindings(targetElement);
relay.SetDataContext(targetElement.DataContext);
}
#endregion
#region MultiBindings attached property
public static MultiBindings GetMultiBindings(DependencyObject obj)
{
return (MultiBindings) obj.GetValue(MultiBindingsProperty);
}
public static void SetMultiBindings(DependencyObject obj, MultiBindings value)
{
obj.SetValue(MultiBindingsProperty, value);
}
public static readonly DependencyProperty MultiBindingsProperty =
DependencyProperty.RegisterAttached("MultiBindings",
typeof (MultiBindings), typeof (BindingUtil), new PropertyMetadata(null, OnMultiBindingsChanged));
/// <summary>
/// Invoked when the MultiBinding property is set on a framework element
/// </summary>
private static void OnMultiBindingsChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
{
FrameworkElement targetElement = depObj as FrameworkElement;
// bind the target elements DataContext, to our DataContextPiggyBack property
// this allows us to get property changed events when the targetElement
// DataContext changes
targetElement.SetBinding(DataContextPiggyBackProperty, new Binding());
MultiBindings bindings = GetMultiBindings(targetElement);
bindings.Initialize(targetElement);
}
#endregion
}
/// <summary>
/// see: http://msdn.microsoft.com/en-us/library/system.windows.data.imultivalueconverter.aspx
/// </summary>
public interface IMultiValueConverter
{
object Convert(object[] values, Type targetType, object parameter, CultureInfo culture);
object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture);
}
/// <summary>
/// Allows multiple bindings to a single property.
/// </summary>
[ContentProperty("Bindings")]
public class MultiBinding : Panel, INotifyPropertyChanged
{
#region ConvertedValue dependency property
public static readonly DependencyProperty ConvertedValueProperty =
DependencyProperty.Register("ConvertedValue", typeof(object), typeof(MultiBinding),
new PropertyMetadata(null, OnConvertedValue));
/// <summary>
/// This dependency property is set to the resulting output of the
/// associated Converter.
/// </summary>
public object ConvertedValue
{
get { return GetValue(ConvertedValueProperty); }
set { SetValue(ConvertedValueProperty, value); }
}
private static void OnConvertedValue(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
{
MultiBinding relay = depObj as MultiBinding;
Debug.Assert(relay != null);
relay.OnPropertyChanged("ConvertedValue");
}
#endregion
#region CLR properties
/// <summary>
/// The target property on the element which this MultiBinding is assocaited with.
/// </summary>
public string TargetProperty { get; set; }
/// <summary>
/// The Converter which is invoked to compute the result of the multiple bindings
/// </summary>
public IMultiValueConverter Converter { get; set; }
/// <summary>
/// The configuration parameter supplied to the converter
/// </summary>
public object ConverterParameter { get; set; }
/// <summary>
/// The bindings, the result of which are supplied to the converter.
/// </summary>
public BindingCollection Bindings { get; set; }
#endregion
public MultiBinding()
{
Bindings = new BindingCollection();
}
/// <summary>
/// Invoked when any of the BindingSlave‘s Value property changes.
/// </summary>
private void SlavePropertyChanged(object sender, PropertyChangedEventArgs e)
{
UpdateConvertedValue();
}
/// <summary>
/// Uses the Converter to update the ConvertedValue in order to reflect
/// the current state of the bindings.
/// </summary>
private void UpdateConvertedValue()
{
List<object> values = new List<object>();
foreach (BindingSlave slave in Children)
{
values.Add(slave.Value);
}
ConvertedValue = Converter.Convert(values.ToArray(), typeof(object), ConverterParameter,CultureInfo.CurrentCulture);
}
/// <summary>
/// Creates a BindingSlave for each Binding and binds the Value
/// accordingly.
/// </summary>
internal void Initialise()
{
Children.Clear();
foreach (Binding binding in Bindings)
{
BindingSlave slave = new BindingSlave();
slave.SetBinding(BindingSlave.ValueProperty, binding);
slave.PropertyChanged += SlavePropertyChanged;
Children.Add(slave);
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
#endregion
}
[ContentProperty("Bindings")]
public class MultiBindings:FrameworkElement
{
private FrameworkElement _targetElement;
public ObservableCollection<MultiBinding> Bindings { get; set; }
public MultiBindings()
{
Bindings = new ObservableCollection<MultiBinding>();
}
#if !SILVERLIGHT
void Loaded(object sender, RoutedEventArgs e)
{
_targetElement.Loaded -= Loaded;
foreach (MultiBinding binding in Bindings)
{
FieldInfo field = _targetElement.GetType().GetField(binding.TargetProperty + "Property", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
if (field == null) continue;
System.Windows.Data.MultiBinding newBinding = new System.Windows.Data.MultiBinding
{
Converter = binding.Converter,
ConverterParameter = binding.ConverterParameter
};
foreach (BindingBase bindingBase in binding.Bindings)
{
newBinding.Bindings.Add(bindingBase);
}
DependencyProperty dp = (DependencyProperty)field.GetValue(_targetElement);
BindingOperations.SetBinding(_targetElement, dp, newBinding);
}
}
#endif
public void SetDataContext(object dataContext)
{
foreach (MultiBinding relay in Bindings)
{
relay.DataContext = dataContext;
}
}
public void Initialize(FrameworkElement targetElement)
{
_targetElement = targetElement;
#if !SILVERLIGHT
_targetElement.Loaded += Loaded;
#else
const BindingFlags DpFlags = BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy;
foreach (MultiBinding relay in Bindings)
{
relay.Initialise();
// find the target dependency property
Type targetType = null;
string targetProperty = null;
// assume it is an attached property if the dot syntax is used.
if (relay.TargetProperty.Contains("."))
{
// split to find the type and property name
string[] parts = relay.TargetProperty.Split(‘.‘);
targetType = Type.GetType("System.Windows.Controls." + parts[0] +
", System.Windows, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e");
targetProperty = parts[1];
}
else
{
targetType = targetElement.GetType();
targetProperty = relay.TargetProperty;
}
FieldInfo[] sourceFields = targetType.GetFields(DpFlags);
FieldInfo targetDependencyPropertyField =
sourceFields.First(i => i.Name == targetProperty + "Property");
DependencyProperty targetDependencyProperty =
targetDependencyPropertyField.GetValue(null) as DependencyProperty;
// bind the ConvertedValue of our MultiBinding instance to the target property
// of our targetElement
Binding binding = new Binding("ConvertedValue") { Source = relay };
targetElement.SetBinding(targetDependencyProperty, binding);
}
#endif
}
}
1、定义两个Converter
//用于多个bool转化为Visibility
public class VisibilityConverter : IMultiValueConverter
{
#region IMultiValueConverter Members
public object Convert(object[] values, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
if (values.Any(value => !(bool) value))
{
return Visibility.Collapsed;
}
return Visibility.Visible;
}
public object[] ConvertBack(object value, Type[] targetTypes,
object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
//多个文本转换
public class TextConverter : IMultiValueConverter
{
#region IMultiValueConverter Members
public object Convert(object[] values, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
return string.Join(", ", values);
}
public object[] ConvertBack(object value, Type[] targetTypes,
object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
2、在Xaml绑定
<phone:PhoneApplicationPage
x:Class="Bomo.Test.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:multiBindingExtend="clr-namespace:Bomo.Test.MultiBindingExtend"
xmlns:test="clr-namespace:Bomo.Test"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<phone:PhoneApplicationPage.Resources>
<test:VisibilityConverter x:Key="VisibilityConverter"></test:VisibilityConverter>
<test:TextConverter x:Key="TextConverter"></test:TextConverter>
</phone:PhoneApplicationPage.Resources>
<!--LayoutRoot 是包含所有页面内容的根网格-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock Text="多路绑定" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>
<TextBlock Text="MultiBinding" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2">
<TextBlock >如果两个开关都打开,方块变红色</TextBlock>
<Grid>
<Rectangle Width="300" Height="30" Fill="#eee" Margin="10"></Rectangle>
<Rectangle Width="300" Height="30" Fill="Red" Margin="10" >
<multiBindingExtend:BindingUtil.MultiBindings>
<multiBindingExtend:MultiBindings>
<multiBindingExtend:MultiBinding TargetProperty="Visibility" Converter="{StaticResource VisibilityConverter}">
<multiBindingExtend:MultiBinding.Bindings>
<multiBindingExtend:BindingCollection>
<Binding Path="Toggle1IsChecked"/>
<Binding Path="Toggle2IsChecked"/>
</multiBindingExtend:BindingCollection>
</multiBindingExtend:MultiBinding.Bindings>
</multiBindingExtend:MultiBinding>
</multiBindingExtend:MultiBindings>
</multiBindingExtend:BindingUtil.MultiBindings>
</Rectangle>
</Grid>
</StackPanel>
<ToggleButton Grid.Row="2" Grid.Column="0" IsChecked="{Binding Toggle1IsChecked, Mode=TwoWay}">开关1</ToggleButton>
<ToggleButton Grid.Row="2" Grid.Column="1" IsChecked="{Binding Toggle2IsChecked, Mode=TwoWay}">开关2</ToggleButton>
</Grid>
<Grid Grid.Row="2">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2">下面文本绑定了两个文本框的内容</TextBlock>
<TextBlock Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Foreground="{StaticResource PhoneAccentBrush}">
<multiBindingExtend:BindingUtil.MultiBindings>
<multiBindingExtend:MultiBindings>
<multiBindingExtend:MultiBinding TargetProperty="Text" Converter="{StaticResource TextConverter}">
<multiBindingExtend:MultiBinding.Bindings>
<multiBindingExtend:BindingCollection>
<Binding Path="Text1"/>
<Binding Path="Text2"/>
</multiBindingExtend:BindingCollection>
</multiBindingExtend:MultiBinding.Bindings>
</multiBindingExtend:MultiBinding>
</multiBindingExtend:MultiBindings>
</multiBindingExtend:BindingUtil.MultiBindings>
</TextBlock>
<TextBox Grid.Row="2" Grid.Column="0" Text="{Binding Text1, Mode=TwoWay}"></TextBox>
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding Text2, Mode=TwoWay}"></TextBox>
</Grid>
</Grid>
</phone:PhoneApplicationPage>
3、后台绑定
public partial class MainPage : INotifyPropertyChanged
{
// 构造函数
public MainPage()
{
InitializeComponent();
}
#region Toggle1IsChecked
/// <summary>
/// The <see cref="Toggle1IsChecked" /> property‘s name.
/// </summary>
public const string Toggle1IsCheckedPropertyName = "Toggle1IsChecked";
private bool _toggle1IsChecked = false;
/// <summary>
/// Sets and gets the Toggle1IsChecked property.
/// Changes to that property‘s value raise the PropertyChanged event.
/// </summary>
public bool Toggle1IsChecked
{
get
{
return _toggle1IsChecked;
}
set
{
if (_toggle1IsChecked == value)
{
return;
}
_toggle1IsChecked = value;
RaisePropertyChanged(Toggle1IsCheckedPropertyName);
}
}
#endregion
#region Toggle2IsChecked
/// <summary>
/// The <see cref="Toggle2IsChecked" /> property‘s name.
/// </summary>
public const string Toggle2IsCheckedPropertyName = "Toggle2IsChecked";
private bool _toggle2IsChecked = false;
/// <summary>
/// Sets and gets the Toggle2IsChecked property.
/// Changes to that property‘s value raise the PropertyChanged event.
/// </summary>
public bool Toggle2IsChecked
{
get
{
return _toggle2IsChecked;
}
set
{
if (_toggle2IsChecked == value)
{
return;
}
_toggle2IsChecked = value;
RaisePropertyChanged(Toggle2IsCheckedPropertyName);
}
}
#endregion
#region Text1
/// <summary>
/// The <see cref="Text1" /> property‘s name.
/// </summary>
public const string Text1PropertyName = "Text1";
private string _text1 = string.Empty;
/// <summary>
/// Sets and gets the Text1 property.
/// Changes to that property‘s value raise the PropertyChanged event.
/// </summary>
public string Text1
{
get
{
return _text1;
}
set
{
if (_text1 == value)
{
return;
}
_text1 = value;
RaisePropertyChanged(Text1PropertyName);
}
}
#endregion
#region Text2
/// <summary>
/// The <see cref="Text2" /> property‘s name.
/// </summary>
public const string Text2PropertyName = "Text2";
private string _text2 = string.Empty;
/// <summary>
/// Sets and gets the Text2 property.
/// Changes to that property‘s value raise the PropertyChanged event.
/// </summary>
public string Text2
{
get
{
return _text2;
}
set
{
if (_text2 == value)
{
return;
}
_text2 = value;
RaisePropertyChanged(Text2PropertyName);
}
}
#endregion
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
#endregion
}
这里只支持到属性的绑定,不支持到UIElement的绑定
本文引用自:http://blog.csdn.net/huangliangjie/article/details/6734099
【WP8】MultiBinding,布布扣,bubuko.com
原文:http://www.cnblogs.com/bomo/p/3616451.html