【发布时间】:2016-02-29 03:46:34
【问题描述】:
TL;DR:
<UserControl.DataContext>
<Foo:Bar>
<Foo:Bar.Baz Blat={Binding Source={RelativeSource Self}, Path=Bing, Mode=TwoWay}"/>
导致以下错误消息:
- System.Windows.Data 警告:40:
- BindingExpression 路径错误:在 'object' 'RelativeSource' (HashCode=38995967)' 上找不到 'Bing' 属性。
- BindingExpression:路径=必应; DataItem='RelativeSource' (HashCode=38995967);
- 目标元素是'Bar' (HashCode=53937671);
- 目标属性是“Baz”(类型“Baz”)`
最终绑定失败 - 为什么?
问题的关键
我有一个相当复杂的ColorModel 类,我在其中继承了DependencyObject 和INotifyPropertyChanged:
[Serializable]
public class ColorModel : DependencyObject, INotifyPropertyChanged {
}
在这个类中有 4 个双精度值 - Alpha、Red、Green 和 Blue:
//The latter 3 DependencyProperties pretty much are the same as this :
public static readonly DependencyProperty
AlphaProperty = DependencyProperty.Register( "Alpha", typeof(double),
typeof(ColorModel), new PropertyMetadata(1.0D));
public double Alpha {
get { return ( double )this.GetValue( AlphaProperty ); }
set {
this.SetValue( AlphaProperty, value );
this.T = Task.WhenAll( new Task[ ] {
this.OnPropertyChanged( "Alpha" ),
this.OnPropertyChanged( "Color" )
} );
}
}
然后是 OnPropertyChanged 方法:
protected async Task OnPropertyChanged( string v ) {
if ( this.PropertyChanged != null )
await this.PropertyChanged.Async(
this, new PropertyChangedEventArgs( v ) ).DontBlock( );
}
最后我有了Color 属性:
public static readonly DependencyProperty
ColorProperty = DependencyProperty.Register( "Color", typeof(Color),
typeof(ColorModel), new PropertyMetadata(Colors.Black));
/// <summary>
/// Get or Set Color Property.
/// </summary>
public Color Color {
get { return ( Color )this.GetValue( ColorProperty ); }
set {
this.SetValue( ColorProperty, value );
this.T = Task.WhenAll( new Task[ ] {
this.OnPropertyChanged("Alpha").DontBlock( ),
this.OnPropertyChanged("Red").DontBlock( ),
this.OnPropertyChanged("Green").DontBlock( ),
this.OnPropertyChanged("Blue").DontBlock( ),
this.OnPropertyChanged("Color").DontBlock( )
} ).DontBlock( );
}
}
不要介意与这个问题无关的异步恶作剧,我已经构建了一个控件,它应该允许用户控制单一颜色的所有方面:
我将每个滑动条双向绑定到我的 ColorModel 的 A/R/G/B 属性:
<Slider
Value="{Binding Alpha, Mode=TwoWay}" .../>
最后,在这个控件 XAML 中,我定义了 DataContext:
<UserControl.DataContext>
<Controls:ColorModel>
<Controls:ColorModel.Color>
<MultiBinding Converter="{StaticResource CMC}">
<Binding Path="Alpha" Mode="TwoWay" Source="{RelativeSource Self}"/>
<Binding Path="Red" Mode="TwoWay" Source="{RelativeSource Self}"/>
<Binding Path="Green" Mode="TwoWay" Source="{RelativeSource Self}"/>
<Binding Path="Blue" Mode="TwoWay" Source="{RelativeSource Self}"/>
</MultiBinding>
</Controls:ColorModel.Color>
</Controls:ColorModel>
</UserControl.DataContext>
这是我正在使用的转换器:
/// <summary>
/// Class For Converting Colors To/From Raw Values.
/// </summary>
public class ColorMultiConverter : IMultiValueConverter {
/// <summary>
/// Convert incoming raw color values into a single color.
/// </summary>
/// <param name="values">
/// [0] : Alpha
/// [1] : Red
/// [2] : Green
/// [3] : Blue
/// </param>
/// <param name="targetType">Color</param>
/// <param name="parameter"></param>
/// <param name="culture"></param>
/// <returns></returns>
public object Convert(
object[ ] values,
Type targetType,
object parameter,
CultureInfo culture ) {
return values.Contains( DependencyProperty.UnsetValue )
? DependencyProperty.UnsetValue
: Color.FromScRgb(
DoubleToFloat( ( double )values[ 0 ] ),
DoubleToFloat( ( double )values[ 1 ] ),
DoubleToFloat( ( double )values[ 2 ] ),
DoubleToFloat( ( double )values[ 3 ] ) );
}
public object[ ] ConvertBack(
object value,
Type[ ] targetTypes,
object parameter,
CultureInfo culture ) {
if ( value == DependencyProperty.UnsetValue )
return new object[ ] {
DependencyProperty.UnsetValue,
DependencyProperty.UnsetValue,
DependencyProperty.UnsetValue,
DependencyProperty.UnsetValue
};
Color C = ( Color )value;
return new object[ ] {
FloatToDouble( C.ScA ),
FloatToDouble( C.ScR ),
FloatToDouble( C.ScG ),
FloatToDouble( C.ScB )
};
}
private float DoubleToFloat( double d ) { return System.Convert.ToSingle( d ); }
private double FloatToDouble( float f ) { return System.Convert.ToDouble( f ); }
}
令我非常懊恼和完全没有惊喜的是,它惨遭失败。当我使用控件加载窗口时,我收到以下错误消息:
- System.Windows.Data 警告:40:
- BindingExpression 路径错误:在“对象”“RelativeSource”(HashCode=38995967)上找不到“Alpha”属性。 BindingExpression:Path=Alpha;
- DataItem='RelativeSource' (HashCode=38995967);
- 目标元素是'ColorModel' (HashCode=53937671);
- 目标属性是“颜色”(类型“颜色”)`
在最长的引入之后,这让我们想到了我的问题 - 我如何将模型的一个属性(或 Multi-Bind,或...无论如何)绑定到该模型的同一实例的另一个属性型号?
【问题讨论】:
标签: c# wpf xaml data-binding datacontext