TL; DR:
<UserControl.DataContext>
<Foo:Bar>
<Foo:Bar.Baz Blat={Binding Source={RelativeSource Self}, Path=Bing, Mode=TwoWay}"/>
导致以下错误消息:
- System.Windows.Data警告:40:
- BindingExpression路径错误:'对象''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路径错误:'object'''RelativeSource'(HashCode = 38995967)'上找不到'Alpha'属性。 BindingExpression:路径=字母;
- DataItem ='RelativeSource'(HashCode = 38995967);
- 目标元素是'ColorModel'(HashCode = 53937671);
- target属性为'Color'(类型'Color')`
在有史以来最长的引导之后,我们将问题带到了我们 - 如何将模型的属性绑定(或多绑定,或者......等)到同一个实例的另一个属性模型?
答案 0 :(得分:0)
好的,所以我能够找到一种方法来做到这一点但是,至少在我有限的理解方面,我能够做到的唯一方法是在ColorModel的构造函数中。
此外,我还在模型的DependencyProperties中添加了一滴代码。
public static readonly DependencyProperty
ColorProperty = DependencyProperty.Register(
"Color",
typeof( Color ),
typeof( ColorModel ),
new PropertyMetadata(
Colors.Black,
async ( S, E ) =>
await ( S as ColorModel ).OnPropertyChanged( "Color" ).DontBlock( ) ) ),
AlphaProperty = DependencyProperty.Register(
"Alpha",
typeof( double ),
typeof( ColorModel ),
new PropertyMetadata(
1.0D,
async ( S, E ) =>
await ( S as ColorModel ).OnPropertyChanged( "Alpha" ).DontBlock( ) ) );
这些DependencyProperties触发对底层ColorModels OnPropertyChanged
方法的调用,以便通过INotifyPropertyChanged
接口绑定的任何内容也会被通知(未经测试,可能是危险的,并且可能会导致灾难性的失败火焰死亡 - 无限火焰环的螺旋)。
然后在构造函数中添加了以下代码:
public ColorModel( ) {
MultiBinding MB = new MultiBinding( );
MB.Converter = new ColorMultiConverter( );
MB.Bindings.Add( new Binding( "Alpha" ) { Source = this, Mode = BindingMode.TwoWay } );
MB.Bindings.Add( new Binding( "Red" ) { Source = this, Mode = BindingMode.TwoWay } );
MB.Bindings.Add( new Binding( "Green" ) { Source = this, Mode = BindingMode.TwoWay } );
MB.Bindings.Add( new Binding( "Blue" ) { Source = this, Mode = BindingMode.TwoWay } );
BindingOperations.SetBinding( this, ColorProperty, MB );
}
这是我能想到的最佳解决方案 - 根据其他答案,尝试使用RelativeSource
仅适用于VisualTree
元素,所以我想这可以解释为什么当我尝试时失败它在XAML中。
答案 1 :(得分:-1)
RelativeSource
仅适用于VisualTree
元素。它不适用于普通的类/属性场景。因此,在您的情况下,RelativeSource
会触及应用DataContext
的控件。
CoerceValueCallback和PropertyChangedCallback用于强制属性之间的关系。
示例,
Slider
控件对其SelectionStart
和SelectionEnd
属性使用值强制。
Slider.SelectionStartProperty = DependencyProperty.Register("SelectionStart", typeof(double), typeof(Slider), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(Slider.OnSelectionStartChanged), new CoerceValueCallback(Slider.CoerceSelectionStart)), new ValidateValueCallback(Slider.IsValidDoubleValue));
private static object CoerceSelectionStart(DependencyObject d, object value)
{
Slider slider = (Slider)d;
double num = (double)value;
double minimum = slider.Minimum;
double maximum = slider.Maximum;
if (num < minimum)
{
return minimum;
}
if (num > maximum)
{
return maximum;
}
return value;
}
同样,您也可以在VM中实现多个属性依赖。
很少有链接: