The attached application shows what the problem is. I built a custom unit system aware input control that converts model values between metric and imperial unit system. After a lot of experimentation and wrestling myself through hundreds of blog posts, support messages etc. I finally found a way to make it work, except for one crucial detail: displaying the correct validation message "value must be between "a"(in/mm) and "b"(in/mm)
I created a custom UnitRangeAttribute
class that handles the validation logic, and I kind of expected this to be picked up by my custom control template, but it doesn't. I suspect this is because I can't use the x:Name="PART_Editor"
on my template, because of the custom EditValue
binding.
The example App shows an entity model with two properties, one with and one without the custom CellTemplate applied. The latter shows the correct message, the former doesn't
For good measure, here's the CellTemplate
I'm talking about.
XAML<DataTemplate x:Key="UnitsAwareInputEditorTemplate">
<dxe:SpinEdit
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Left"
EditValue="{Binding Value, Converter={converters:LengthUnitConverter}}"
Mask="{Binding UnitsFormatString, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindow}}}"
MaskType="Numeric"
MaskUseAsDisplayFormat="True"
MaxValue="{Binding Converter={converters:RangeAttributeConverter}, ConverterParameter=Max}"
MinValue="{Binding Converter={converters:RangeAttributeConverter}, ConverterParameter=Min}"
ShowBorder="False" />
</DataTemplate>
And this is the custom attribute:
C#[AttributeUsage(AttributeTargets.Property)]
public class UnitRangeAttribute : ValidationAttribute
{
private readonly UnitSystem _unitSystem = UnitSystemProvider.FromDiContainer;
private readonly double _minimum;
private readonly double _maximum;
public UnitRangeAttribute(double minimum, double maximum)
{
_minimum = minimum;
_maximum = maximum;
ErrorMessage = $"Value for {0} is not in the expected range {Minimum} - {Maximum}";
}
public double Minimum => UnitSets.Length.FromMetric(_minimum, _unitSystem);
public double Maximum => UnitSets.Length.FromMetric(_maximum, _unitSystem);
public override bool IsValid(object value)
{
if (value is not double doubleValue)
throw new ArgumentException("Value must be a double");
double enteredValue = UnitSets.Length.FromMetric(doubleValue, _unitSystem);
return enteredValue >= Minimum && enteredValue <= Maximum;
}
public override string FormatErrorMessage(string name)
{
return string.Format(ErrorMessageString, name, Minimum, Maximum);
}
}
I even have an alternative implementation of this Attribute commented out in the attached source code, you can have a look at it, but it also did'nt work.
I don't know what I'm missing, so please help me out here!
Much appreciated!
Kind regards,
Gert
Hello Gert,
Thank you for the sample project.
To synchronize the editor with
PropertyGridControl
and utilize its validation mechanism, you need to nameSpinEdit
asPART_Editor
, even if you bind theEditValue
property. This appears to be the most straightforward solution for your task.That being said, since you define
MinValue
andMaxValue
at the editor level, the editor's internal validation overridesPropertyGridControl
's logic even in this case. To utilize custom validation instead, you need to removeMinValue
andMaxValue
definitions:<DataTemplate x:Key="UnitsAwareInputEditorTemplate"> <dxe:SpinEdit x:Name="PART_Editor" HorizontalAlignment="Stretch" HorizontalContentAlignment="Left" EditValue="{Binding Value, Converter={converters:LengthUnitConverter}}" Mask="{Binding UnitsFormatString, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindow}}}" MaskType="Numeric" MaskUseAsDisplayFormat="True" ShowBorder="False" /> </DataTemplate>
Please let me know if this helps.
Regards,
Alexander
Hi Alexander,
Thanks for the quick reply. If it were only this simple . For good measure, I have tried your suggestion, but sadly it does not work.
If you add the
PART_Editor
back, the whole binding is screwed up, because of the converter applied to it. Try it yourself. Change the value in theHeight
field, leave it to commit the value and then come back to it, notice what happens to the value. Note: the debug output shows the value that gets written into the Entity model property, monitor it when you're changing the value.If you remove the min and max value, the spin-edit no longer stops at the min and max values. Also, the bindings are necessary for the min and max values to work in the designated unit system, so between 100 and 400 in metric and 3.xxx and 15.xxx when in imperial
Please also note that both manual data entry and using the up/down buttons on the spin edit control should be supported.
Trust me, I worked on this for days and have a few bald spots on my head as a result of pulling my hair out while trying to get all these requirements to work at the same time.
I'm very interested to see if there is an easy way to get this all working. Please make me happy
Kind regards,
Gert