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");
}
}
}

BindingCollection

    /// <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 }

BindingSlave

    /// <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 }

BindingUtil

    /// <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);
}

IMultiValueConverter

    /// <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
}

MultiBinding

    [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[] +
", System.Windows, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e");
targetProperty = parts[];
}
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
}
}

MultiBindings

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
}

Converter

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>

MainPage.xaml

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
}

MainPage.xaml.cs

这里只支持到属性的绑定,不支持到UIElement的绑定

本文引用自:http://blog.csdn.net/huangliangjie/article/details/6734099

【WP8】MultiBinding的更多相关文章

  1. 【WP8】WebBrowser相关

    2014年09月02日更新 今天用了一下WebBrowser,在使用过程中也遇到了一些问题,在这里做一下记录 虽然WebBrowser比较重,会比较影响性能(除非一定要用到它,否则尽量少用),但有时候 ...

  2. 【WP8】线程安全的StorageHelper

    14-08-29 12:32更新:修复StorageHelper部分bug WP8以后提供了StorageFile的方式访问文件,StorageFile对文件的操作只提供了异步的支持,包括WP8.1 ...

  3. 【WP8】让TextBox文本支持滑动(Scroll)

    通过修改样式让TextBox支持文本滑动 在Silverlight上,TextBox是有文本滚动的功能的,当TextBox的文本过长时,可以进行拖动的,TextBox使用 VerticalScroll ...

  4. 【WP8】自定义配置存储类

    之前在WP7升级到WP8的时候遇到配置不兼容的问题 情景:之前只有一个WP7版本,现在需要发布WP8版本,让用户可以从原来的WP7版本升级到WP8版本 一般情况下从WP7升级到WP8没什么问题 但是在 ...

  5. 【WP8】ResourceDictionary

    WP8中引用资源字典 当我们定义的样式太多的时候,我们可以把样式分别定义在不同的文件中,然后通过 MergedDictionaries 应用到其他资源字典中,看下面Demo 我们可以把样式定义在多个文 ...

  6. 【WP8】LoopingSelector

    WP8的WindowsPhoneToolkit工具包中有一个 LoopingSelector 可以想选择日期或时间一样进行选择 1.首先当然是引用WindowsPhoneToolkit 在Nuget控 ...

  7. 【WP8】为Webbrowser添加ScrollBar

    在WP8中,控件WebBrowser没有提供对滚动条的支持,而在内置的IE中,却可以显示出滚动条(微软这是在坑我们吗),但如果在客户端使用Webbrowser的话,自己构造ScrollBar来显示 通 ...

  8. 【WP8】Uri关联启动第三方App

    在WP8中支持启动第三方应用程序,比如在App1中可以打开App2,你可以在你的应用程序中直接打开QQ,也可以让其他开发者调用你的APP,例如:软件盒子 下面演示被调用方和调用方的使用方法,新建两个项 ...

  9. 【WP8】WP8调用官方API使用LED灯

    在WP7中没有相关的API可以直接使用摄像头的LED等,只能通过录像时打开LED等来使用,在WP8中添加了相关的调用接口,可以方便的使用LED灯,并且支持后台,废话不多说,直接上代码 1.在 WMAp ...

随机推荐

  1. JAVA-JSP内置对象之pageContext对象取得不同范围属性

    相关资料:<21天学通Java Web开发> pageContext对象取得不同范围属性 pageContextDemo.jsp <%@ page language="ja ...

  2. iOSTableview 禁止下拉,允许上拉

    1 回弹机制:bounces alwaysBounceHorizontal alwaysBounceVerticalbounces:描述的当scrollview的显示超过内容区域的边缘以及返回时,是否 ...

  3. [转]我的MYSQL学习心得(六) 函数

    这一节主要介绍MYSQL里的函数,MYSQL里的函数很多,我这里主要介绍MYSQL里有而SQLSERVER没有的函数 数学函数 1.求余函数MOD(X,Y) MOD(X,Y)返回x被y除后的余数,MO ...

  4. jQuery Validate验证方法及教程

    //实名认证 验证 $(function(){ //中文姓名验证 jQuery.validator.addMethod("zh_verify", function(value, e ...

  5. 点击页面任一地方,js发生响应!

    document.onmousedown = closeAll; function closeAll() { alert("aaaaaaaaaaaa"); }

  6. hive常用参数配置设置

    hive.exec.mode.local.auto 决定 Hive 是否应该自动地根据输入文件大小,在本地运行(在GateWay运行) true hive.exec.mode.local.auto.i ...

  7. java随机范围内的日期

    使用了最新的java8的java.time类,并提供了LocalDateTime和java.util.Date之间的转换. 使用方法: randomLocalDateTime(-3,3) : 取距离今 ...

  8. Mac 添加ll命令

    执行 vim ~/.bash_profile 该文件有可能不存在,直接编辑即可. 在文件中加入: alias ll='ls -alF' 再执行 source ~/.bash_profile

  9. LDAP none、simple、strong 笔记

    // 该笔记仍在调研中!!不确保中有错误信息!最终目的是想用java实现这三种认证方式. 1.ldaps://  注意多了个s 参考:https://mail.python.org/pipermail ...

  10. 微信小程序的json遍历

    入门教程之列表渲染多层嵌套循环,目前官方的文档里,主要是一维数组列表渲染的案例,还是比较简单单一,给刚入门的童鞋还是无从入手的感觉. <view wx:for="{{items}}&q ...