Я использую ValidationRule динамически в FooBox (обновленное текстовое поле).
Он работает нормально, когда используется непосредственно в окне.
У меня есть другой пользовательский элемент управления (LatLonEditor) для управления широтой и долготой с помощью FooBox.
В этом конкретном случае, когда я получаю привязку значения FooBox, я всегда получаю привязку первого FooBox первого LatLonEditor.
Я провел день, пытаясь это исправить, и у меня заканчиваются решения.
Я прочитал исходный код 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
(При первом связывании применяется правило второго элемента управления)
Я, конечно, что-то упускаю, но я не вижу что? : - (