Recently I’m working on a LOB (Line-of-Business) application requires implementing couple of survey forms to collect data from the user (yes, in addition to sell our software products, we provide .Net consulting service too). Here is a clean implementation I came up with - for simplicity, the WCF web service and database access part is omitted.
The Data Model
The SurveyData class represents the data of one survey, which contains a collection of SurveyItem objects. One SurveyItem has two parts: definition (Key, AnswerType, MinValue, MaxValue) and answer (AnswerBit, AnswerNum, AnswerText). The definition of the SurveyItem defines the parent/child relationship between survey items through its Key property, the answer type of the survey item, and the Min/Max value of the allowed answer. A handy Excel file (SurveyItem.xls in the downloadable source) was created to define SurveyItem objects, and formulas are created to generate C# code to initialize the data. Take a look at “Read Me” worksheet to get detailed information on how to define SurveyItem objects.
The Data Validation
The combination of definition properties sets constraints of SurveyItem, and SurveyData.Validate method validates all contained SurveyItem objects against their constraints, results in values of SurveyItem.HasError and SurveyItem.Error properties. For better user experience, the data validation is implemented as the following:
- Data is not validated until the first call to SurveyData.Validate.
- After SurveyData.Validate called for the first time, every SurveyItem property change results in a SurveyData.Validate call.
Note the validation is done against the data only, and has nothing to do with the presentation.
The presentation (SurveyForm.xaml) is pretty straightforward then. An instance of SurveyData is set to SurveyForm.DataContext, and the UI elements (TextBlock, Checkbox, TextBox, etc) are data binding to the contained SurveyItem object. The UI elements are also styled to indicate if there is a data validation error: if an error exists, its foreground color is changed to red and its tooltip contains the error message.
Note: The designer does not execute code behind, so settiing the SurveyData as DataContext in code behind results in data binding error in Visual Studio designer. To workaround, we create a SurveyFormBase class, set the DataContext in this class, and derive SurveyForm class from SurveyFormBase.