1

I've one ViewModel that has a property. This property is a "PhysicalValue". This PhysicalValue is a class that is composed from a Value and an Unit.

public Class MyViewModel:INotifyPropertyChanged:IDataErrorInfo {
    public PhysicalValue Target {get => _target; set => {_target = value; NotifyPropertyChanged("Target");}}

    public string this[string columnName]
    {
        get
        {
            if (columnName == "Target")
            {
                if(_target.Value>5000){
                    return "out of spec value";
                }
            }
            return String.Empty;
        }
    }   
}

I've one control that should edit the value of this PhysicalValue:

[...]
<dxe:TextEdit EditValue="{Binding Target.Value, ValidatesOnDataErrors =true}"></dxe:TextEdit>
[...]

But I've no error for it(probably because it search for Target.Value for an error. I've tried another approach, bind directly to Target, but this doesn't work, because I need the convertBack to known which Unit was used originally to rebuild a PhysicalValue.

How would you solve this?

J4N
  • 19,480
  • 39
  • 187
  • 340
  • There is an example here, would it be website I would just use some client side or html5 for input validation as to not over-engineer.. https://stackoverflow.com/a/14023682/10634638 – estinamir Feb 21 '19 at 15:02
  • @Bestinamir Not sure to understand your answer. It's not a layout issue. – J4N Feb 21 '19 at 15:12
  • What kind of error do you want to generate? Are you able to set the Value property? – mm8 Feb 21 '19 at 15:54

1 Answers1

1

The EditValue property of your TextEdit control is bound to PhysicalValue.Value. When you set Binding.ValidatesOnDataErrors to true, the binding engine checks if the class that has the target property implements IDataErrorInfo. So for this to work the PhysicalValue class needs to implement IDataErrorInfo:

class PhysicalValue : IDataErrorInfo
{
    public double Value { get; set; }

    public object Unit { get; set; }

    public string Error => this["Value"] + this["Unit"];

    public PhysicalValue(int v, object u)
    {
        Value = v;
        Unit = u;
    }

    public string this[string columnName]
    {
        get
        {
            if (columnName == "Value")
            {
                if (Value > 5000)
                {
                    return "out of spec value";
                }
            }
            return String.Empty;
        }
    }
}

If the PhysicalValue class can not hold the validation logic or can not implement the IDataErrorInfo interface you could create a proxy class that handles the validation and bind to that instead. Here is a small example:

class PhysicalValueValidator : IDataErrorInfo
{
    private readonly PhysicalValue _physicalValue;
    private double _maxValue;

    public double Value
    {
        get { return _physicalValue.Value; }
        set { _physicalValue.Value = value; }
    }

    public PhysicalValueValidator(PhysicalValue pv)
    {
        _physicalValue = pv;
        _maxValue = 5000;
    }

    public void SetMaxValue(double maxValue)
    {
        _maxValue = maxValue;
    }

    public string this[string columnName]
    {
        get
        {
            if (columnName == "Value")
            {
                if (Value > _maxValue)
                {
                    return "out of spec value";
                }
            }
            return String.Empty;
        }
    }

    public string Error => this["Value"];
}

The PhysicalValueValidator class exposes the SetMaxValue(..) method to update the validation logic from your panes viewmodel. The viewmodel could look like this:

class MyViewModel 
{
    private PhysicalValue _target;

    public PhysicalValueValidator TargetValidator { get; }

    public MyViewModel()
    { 
        _target = new PhysicalValue(5, 10);
        TargetValidator = new PhysicalValueValidator(_target);

        // update validation Logic...
        TargetValidator.SetMaxValue(6000);
    }
}

In your xaml code, bind to TargetValidator.Value instead of Target.Value.

For more information on IDataErrorInfo check this link: IDataErrorInfo

Tobias Hoefer
  • 1,058
  • 12
  • 29
  • Yeah, the issue is that this limit of 5000 is really specific to my usage in this pane. We use this PhysicalValue at a lot of places, and the physical value cannot know currently if it's valid. It required calling some method to compute some hardware power limitation with big equations that doesn't only depends on this value :( – J4N Feb 22 '19 at 06:40
  • 1
    Ok, if the validation logic is not specific to PhysicalValue but to your pane you could create a proxy class that handles the validation. I will update my answer with a short example – Tobias Hoefer Feb 22 '19 at 13:46
  • That's a really nice idea, very smart and clean, I love it! Thank you very much! – J4N Feb 25 '19 at 06:48