.net - BindingOperations.GetBinding 给出另一个绑定
问题描述
我在 FooBox (升级的文本框)中动态使用 ValidationRule。直接在窗口中使用时它工作正常。
我有另一个自定义控件(LatLonEditor)来使用 FooBox 管理纬度和经度。在这种特殊情况下,当我获得 FooBox 值的绑定时,我总是获得第一个 LatLonEditor 的第一个 FooBox 的绑定。
我花了一天时间试图解决这个问题,但我的解决方案已经用完了。我已经阅读了 BindingOperations.GetBinding 源代码(没有给我任何线索)。我创建了一个独立的项目来重现剥离代码中所有无用部分的问题。
FooBox 模板
<ControlTemplate x:Key="FooBoxTemplate" TargetType="{x:Type local:FooBox}">
<TextBox x:Name="Editor" Text="{Binding Path=Value, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Margin="0,0,1,0" />
<ControlTemplate.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self},
Path=(Validation.Errors).CurrentItem.ErrorContent}"/>
<Setter Property="BorderBrush" TargetName="Editor" Value="Red" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style x:Key="DefaultFooBoxStyle" TargetType="{x:Type local:FooBox}">
<Setter Property="Template" Value="{StaticResource FooBoxTemplate}"/>
<Setter Property="Height" Value="24" />
<Setter Property="Validation.ErrorTemplate" Value="{x:Null}" />
<Setter Property="Focusable" Value="False" />
</Style>
<Style TargetType="{x:Type local:FooBox}" BasedOn="{StaticResource DefaultFooBoxStyle}" />
FooBox 控件
public class FooBox : Control
{
static FooBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(FooBox), new FrameworkPropertyMetadata(typeof(FooBox)));
}
public enum Type
{
Int,
Float,
Double,
String
}
private bool _templateApplied = false;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_templateApplied = true;
LoadValidationRules();
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(string), typeof(FooBox), new FrameworkPropertyMetadata()
{
BindsTwoWayByDefault = true,
DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
});
public string Value
{
get { return (string)GetValue(ValueProperty); }
set
{
SetValue(ValueProperty, value);
}
}
public static readonly DependencyProperty ValueTypeProperty =
DependencyProperty.Register("ValueType", typeof(Type), typeof(FooBox), new FrameworkPropertyMetadata()
{
DefaultValue = Type.String
});
public Type ValueType
{
get { return (Type)GetValue(ValueTypeProperty); }
set
{
SetValue(ValueTypeProperty, value);
}
}
/// <summary>
/// For integral types, this is the max acceptable value
/// </summary>
public static readonly DependencyProperty DomainMaxProperty =
DependencyProperty.Register("DomainMax", typeof(decimal?), typeof(FooBox), new FrameworkPropertyMetadata());
public decimal? DomainMax
{
get { return (decimal?)GetValue(DomainMaxProperty); }
set
{
SetValue(DomainMaxProperty, value);
}
}
private void LoadValidationRules()
{
if (_templateApplied)
{
//For the second LatLonEditor, i've got the binding of the previous one
Binding b = BindingOperations.GetBinding(this, ValueProperty);
if (b != null)
{
b.ValidationRules.Clear();
if (ValueType == Type.Double)
{
b.ValidationRules.Add(new DoubleValidationRule()
{
DomainMax = DomainMax
});
}
}
}
}
}
LatLonEditor 模板
<ControlTemplate x:Key="LatLonDecimalDegreesEditorTemplate" TargetType="{x:Type local:LatLonEditor}">
<local:FooBox x:Name="PART_DD" ValueType="Double" Margin="2,0"
Value="{Binding Value, Delay=500, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged,
RelativeSource={RelativeSource TemplatedParent}}"/>
<ControlTemplate.Triggers>
<Trigger Property="Type" Value="Latitude">
<Setter TargetName="PART_DD" Property="DomainMax" Value="90" />
</Trigger>
<Trigger Property="Type" Value="Longitude">
<Setter TargetName="PART_DD" Property="DomainMax" Value="180" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style x:Key="DefaultLatLonEditorStyle" TargetType="{x:Type local:LatLonEditor}">
<Setter Property="Template" Value="{StaticResource LatLonDecimalDegreesEditorTemplate}"/>
</Style>
<Style BasedOn="{StaticResource DefaultLatLonEditorStyle}" TargetType="{x:Type local:LatLonEditor}" />
LatLonEditor 控件
public class LatLonEditor : Control
{
#region Statements
#endregion
#region Constructor/Destructor
static LatLonEditor()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(LatLonEditor), new FrameworkPropertyMetadata(typeof(LatLonEditor)));
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
}
#endregion
/// <summary>
/// The types of value that can be input
/// </summary>
public enum CoordinateValueType : byte
{
Latitude,
Longitude
}
#region Properties
/// <summary>
/// Get/Set the input mode for this instance
/// </summary>
public static readonly DependencyProperty TypeProperty =
DependencyProperty.Register("Type", typeof(CoordinateValueType), typeof(LatLonEditor), new FrameworkPropertyMetadata()
{
DefaultValue = CoordinateValueType.Latitude
});
public CoordinateValueType Type
{
get { return (CoordinateValueType)GetValue(TypeProperty); }
set { SetValue(TypeProperty, value); }
}
/// <summary>
/// Formatted value to use externally
/// </summary>
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(double?), typeof(LatLonEditor), new FrameworkPropertyMetadata());
public double? Value
{
get
{
return (double?)GetValue(ValueProperty);
}
set
{
SetValue(ValueProperty, value);
}
}
#endregion
}
用法
<controls:LatLonEditor x:Name="H3LP" Width="120" Type="Longitude" Value="3" />
<controls:LatLonEditor x:Name="IfYouPlease" Width="120" Type="Latitude" Value="5" />
第一个 LatLonEditor 的最大值应为 180 第二个 LatLonEditor 的最大值应为 90
触发器正确设置了 DomainMax。
实际结果是两个控件的最大值都是90(第一个绑定应用第二个控件的规则)
我当然错过了一些东西,但我没有看到什么?:-(
解决方案
You should first get a reference to the element to which you have applied the binding and then use BindingOperations.GetBinding
:
private void LoadValidationRules()
{
if (_templateApplied)
{
TextBox Editor = Template.FindName("Editor", this) as TextBox;
Binding b = BindingOperations.GetBinding(Editor, TextBox.TextProperty);
if (b != null)
{
...
}
}
}
Since a Binding
is not supposed to be modified you might also create the initial binding programmatically:
private void LoadValidationRules()
{
if (_templateApplied)
{
TextBox Editor = Template.FindName("Editor", this) as TextBox;
Binding b = new Binding(nameof(Value)) { Source = this };
if (ValueType == Type.Double)
{
b.ValidationRules.Add(new DoubleValidationRule()
{
//DomainMax = DomainMax
});
}
BindingOperations.SetBinding(Editor, TextBox.TextProperty, b);
}
}
Then you will certainly get a unique binding per instance.
推荐阅读
- javascript - Handlebars:访问已被拒绝解析“来自”的属性,因为它不是其父级的“自己的属性”
- python-3.x - 在使用 iterrows 进行迭代时比较数据框中的两个值
- javascript - React/Express: POST 错误 413: Payload too large (Bodyparser 不工作)
- flutter - Flutter Navigation 重新渲染历史堆栈页面中的所有页面
- reactjs - React Hook useState 不更新 UI
- loops - 尝试登录我的 Elementary OS 密码时遇到挑战
- python - 如何通过 Scrapy 收集 jpeg
- javascript - 有没有办法让两个函数同名?
- python - 如何在 BeautifulSoup 4 中找到明文兄弟?
- r - 如何将特定的'NA'值(不是全部'NA')替换为R数据框中的特定数值?