tags:

views:

239

answers:

3

I would like to display warnings and errors when validating a business object and have these displayed visually to the user.

For example I have a business object class implementing an interface like so:

interface IOrderItem : IDataErrorInfo
{
  int ProductId { get; set; }
  string ProductName { get; set; }
  decimal Price { get; set; }
  IDictionary<string, string> Warnings { get; }
}

This is bound to the UI as follows:

<TextBox Text="{Binding Price, ValidatesOnDataErrors=True}/>

An error would be:

  • Price < 0 => "Price cannot be less than 0"

This works nicely and draws a red border around the textbox when I put the error message on the business object using the IDataErrorInfo interface.

What I would like to do is also specify warnings, for example:

  • Price < 15 || Price > 30 => "Price outside of tolerance"

These warnings would put an orange border around a text box and inform the user that there may be a problem but not stop them proceeding.

The warnings are stored in a string dictionary mapping PropertyName => WarningMessage in a similar way to IDataErrorInfo.

Question: What is the best way to go about this?

  • Obviously I will need a Style that contains an orange border for the text box but how do I trigger it?
  • I don't really want a seperate style for each textbox, so how can the style access the underlying binding to get the property name it should look up in the Dictionary.
+1  A: 

Have you checked this http://www.codeproject.com/KB/WPF/wpfvalidation.aspx

EDIT: Please find the sample here http://www.filefactory.com/file/b3b4cb7/n/ValidationErrorsSample.zip

HTH

Avatar
The ErrorProvider located in that project seems to center around alternate ways of raising errors, rather than ways to differentiate errors from warnings.
GWLlosa
You are right. This looks way big than I looked. But, You can achieve this by tagging the exception data with required value.
Avatar
@GWLlosa I have updated my post please check.
Avatar
I can't get to FileFactory from my current site; I'll check on it in about 2 hours or so.
GWLlosa
A: 

One good way to do this is a custom style that had datatriggers on a validation property (possibly leavearge VSM and gotostateaction.

Example from one of my projects:

<i:Interaction.Triggers>
  <ei:DataTrigger Binding="{Binding UnitData.TestState}" Value="Unknown">
      <ei:GoToStateAction StateName="UnknownState"/>
  </ei:DataTrigger>
  <ei:DataTrigger Binding="{Binding UnitData.TestState}" Value="Pass">
      <ei:GoToStateAction StateName="PassState"/>
  </ei:DataTrigger>
  <ei:DataTrigger Binding="{Binding UnitData.TestState, Mode=OneWay}" Value="Fail">
      <ei:GoToStateAction StateName="FailState"/>
  </ei:DataTrigger>
  <ei:DataTrigger Binding="{Binding UnitData.TestState, Mode=OneWay}" Value="Terminated">
      <ei:GoToStateAction StateName="FailState"/>
  </ei:DataTrigger>
  <ei:DataTrigger Binding="{Binding UnitData.TestState, Mode=OneWay}" Value="Warn">
     <ei:GoToStateAction StateName="WarnState"/>
  </ei:DataTrigger>
  <ei:DataTrigger Binding="{Binding UnitData.TestState}" Value="Indeterminate">
      <ei:GoToStateAction StateName="IndeterminateState"/>
  </ei:DataTrigger>
</i:Interaction.Triggers>
Firoso
You're binding here to UnitData.TestState. The idea I'm after is to be able to effectively reproduce your binding, without knowing the name of the property (UnitData.TestState) until runtime, preferably by somehow re-using the current value binding of the current column.
GWLlosa
nothing preventing you from doing an element binding + path.
Firoso
That sounds very much like what I'm trying to get at; do you have an example of the syntax for referring to your own binding?
GWLlosa
TestEntry="{Binding SelectedItem.ValidationState, ElementName=testListBox}"
Firoso
A: 

CSLA.Net has a control called PropertyStatus that is used for this purpose (Error, Warning, or Information), as well as additional functionality tied to the rest of CSLA. But you might look at the code (open source) for how it is handled there.

It seems like you could also use a converter on the border color bound to the object (or warning dictionary, but with the whole object you could handle the errors through IDataErrorInfo as well) with a converter parameter to specify the property to check for. I'm sure you could simplify this further with some fanciness using element binding syntax or something. The converter would return the color you wanted to display.

Turntwo