void ParseTargetProperty()
{
TargetDependencyProperty = null;
if (string.IsNullOrEmpty(TargetProperty) || AssociatedObject == null)
return;
var sourceDependencyPropertyField = AssociatedObject.
GetType().GetField(TargetProperty + "Property");
if (sourceDependencyPropertyField != null)
{
TargetDependencyProperty = sourceDependencyPropertyField.
GetValue(null) as DependencyProperty;//獲取依賴屬性
}
TargetPropertyInfo = AssociatedObject.GetType().GetProperty(TargetProperty);//獲取屬性的反射器
if (TargetPropertyInfo != null)
TargetPropertyType = TargetPropertyInfo.PropertyType;
}
由於控件上的屬性大多是依賴屬性,直接通過依賴屬性賦值會快的多。各別非依賴屬性則只能依靠反射器賦值了。這裏
public class BindingSource : DependencyObject
{
#region Value
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(object), typeof(BindingSource),
new PropertyMetadata(null, OnValueChanged));
public object Value
{
get { return GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
private static void OnValueChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
{
BindingSource slave = depObj as BindingSource;
if (slave != null)
slave.OnValueChanged();
}
#endregion
#region Binding Property
public bool BindsDirectlyToSource { get; set; }
public IValueConverter Converter { get; set; }
public CultureInfo ConverterCulture { get; set; }
public object ConverterParameter { get; set; }
public string ElementName { get; set; }
public BindingMode Mode { get; set; }
public bool NotifyOnValidationError { get; set; }
public string Path { get; set; }
public RelativeSource RelativeSource { get; set; }
public object Source { get; set; }
public UpdateSourceTrigger UpdateSourceTrigger { get; set; }
public bool ValidatesOnDataErrors { get; set; }
public bool ValidatesOnExceptions { get; set; }
public bool ValidatesOnNotifyDataErrors { get; set; }
#endregion
Binding _binding;
public event Action<object, object> ValueChanged;
protected void OnValueChanged()
{
var hander = this.ValueChanged;
if (hander != null)
{
hander(this, Value);
}
}
public void Init()
{
_binding = new Binding();
_binding.BindsDirectlyToSource = this.BindsDirectlyToSource;
_binding.Converter = this.Converter;
_binding.ConverterCulture = this.ConverterCulture;
_binding.ConverterParameter = this.ConverterParameter;
if (!string.IsNullOrEmpty(this.ElementName))
{
_binding.ElementName = this.ElementName;
}
_binding.Mode = this.Mode;
_binding.NotifyOnValidationError = this.NotifyOnValidationError;
_binding.Path = new PropertyPath(this.Path);
if (string.IsNullOrEmpty(_binding.ElementName) && this.RelativeSource != null)
{
_binding.RelativeSource = this.RelativeSource;
}
if (string.IsNullOrEmpty(_binding.ElementName) && this.RelativeSource == null)
{
_binding.Source = this.Source;
}
_binding.UpdateSourceTrigger = this.UpdateSourceTrigger;
_binding.ValidatesOnDataErrors = this.ValidatesOnDataErrors;
_binding.ValidatesOnExceptions = this.ValidatesOnExceptions;
_binding.ValidatesOnNotifyDataErrors = this.ValidatesOnNotifyDataErrors;
BindingOperations.SetBinding(this, ValueProperty, _binding);
}
}
public class BindingCollection : DependencyObjectCollection<BindingSource>
{
public event Action<object, object> HasValueChanged;
public BindingCollection()
{
this.CollectionChanged += BindingCollection_CollectionChanged;
}
void BindingCollection_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null && e.NewItems.Count > 0)
{
foreach (BindingSource binding in e.NewItems)
{
binding.Init();
binding.ValueChanged += binding_ValueChanged;
}
}
if (e.OldItems != null && e.OldItems.Count > 0)
{
foreach (BindingSource binding in e.OldItems)
{
binding.ValueChanged -= this.binding_ValueChanged;
}
}
}
void binding_ValueChanged(object sender, object value)
{
var hander = this.HasValueChanged;
if (hander != null)
{
hander(sender, value);
}
}
}
剩下的就是將綁定列表通過轉換器後更新界面了: internal void Source_ValueChanged(object sender, object value)
{
if (Converter == null || AssociatedObject == null || (TargetDependencyProperty == null && TargetPropertyInfo == null))
return;
var targetValue = Converter.Convert(Bindings, TargetPropertyType, ConverterParameter, null);
if (TargetDependencyProperty != null)//若目標是依賴屬性則直接賦值
{
AssociatedObject.SetValue(TargetDependencyProperty, targetValue);
}
else if (TargetPropertyInfo != null && TargetPropertyInfo.CanWrite)//非依賴屬性通過反射器賦值
{
TargetPropertyInfo.SetValue(this.AssociatedObject, targetValue, null);
}
}
使用的時候需要自定義一個轉換器: public class NameConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo language)
{
var values = value as BindingCollection;
if (values == null || values.Count < 2)
return "";
return string.Format("{0}.{1}", values[0].Value, values[1].Value);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo language)
{
return "";
}
}
然後xaml中這樣使用就可以了: <TextBlock Margin="10" Height="80" VerticalAlignment="Top">
<local:MultiBindings.BindinCollection>
<local:MultiBinding TargetProperty="Text" Converter="{StaticResource NameConverter}">
<local:BindingSource Path="FristName" Source="{StaticResource ViewModel}"/>
<local:BindingSource Path="SecondName" Source="{StaticResource ViewModel}"/>
</local:MultiBinding>
</local:MultiBindings.BindinCollection>
</TextBlock>
界面效果
下面的2個按鈕點一下上面對應的值+1