Lets say I have a set of model classes like this:
public class Person
{
public string Name { get; set; }
public ObservableCollection<Job> Jobs { get; private set; }
}
public class Job
{
public string Title { get; set; }
public DateTime? Start { get; set; }
public DateTime? End { get; set; }
}
I set up my xaml like this to display a list of people and all details on a single view:
<StackPanel Orientation="Horizontal">
<ListView ItemsSource="{Binding}" Width="200" DisplayMemberPath="Name" IsSynchronizedWithCurrentItem="True" />
<DockPanel Width="200" Margin="10,0">
<TextBox Text="{Binding Name}" DockPanel.Dock="Top" Margin="0,0,0,10"/>
<ListView ItemsSource="{Binding Jobs}" Name="_jobList" DisplayMemberPath="Title" IsSynchronizedWithCurrentItem="True"/>
</DockPanel>
<StackPanel Width="200" DataContext="{Binding ElementName=_jobList, Path=SelectedItem}">
<TextBox Text="{Binding Title}"/>
<DatePicker SelectedDate="{Binding Start}"/>
<DatePicker SelectedDate="{Binding End}"/>
</StackPanel>
</StackPanel>
The DataContext for the entire Window is an ObservbleCollection of People. This seems to work fairly well. I would now like to add some validation and I have no idea where to start.
I would like to validate the Job fields so that the user cannot select another Job (or person) if the title is empty or a duplicate within the same person, or if the dates are out of order. Additionally, the Person cannot be changed if the name is empty.
I have read a bit about validation in WPF, but have not found any clear solution for this scenario. What is the best practice for doing something like this?
Also, is my binding ok the way I set the DataContext on the last panel like that? It works, but it feels a little sketchy. The alternative is declaring resources for the CollectionDataSources and I couldn’t really figure that method out very easily either.
For the validation part you can start here: http://codeblitz.wordpress.com/2009/05/08/wpf-validation-made-easy-with-idataerrorinfo/
After you understand the article you could modify your classes like this:
For example let’s add a non-empty title validation for job title and job start date:
Job class:
//////////Supposing we used a window called MainWindow for you xaml code it would look like
MainWindow.xaml
////////MainWindow.xaml.cs
//////////////////////
One simple solution is to disable the listboxes if the forms has errors (that’s what I did in the code above), and enable them when there are no errors. Also you should probably put a nice red border with tooltip on them, explaining the user why he can’t select anymore.
For validating if the title is duplicate within the same person, you could extend the validation mechanism above to have a ValidationService class that receives a Person and looks if the person who has the job also has another one with the same name.
public class Person: IDataErrorInfo
{
It’s not in the MVVM spirit, and if what you’re doing is going to be something more than a small test project you should try learn MVVM (You could start here: http://fernandomachadopirizen.wordpress.com/2010/06/10/a-simple-introduction-to-the-model-view-viewmodel-pattern-for-building-silverlight-and-windows-presentation-foundation-applications/)
Then you would not bind to a list of persons directly but instead you would have some MainWindowViewModel class to which you bind. This MainWindowViewModel class would contain the list of persons and you would bind to that.
And for the selection you would have a CurrentJob property in your MainWindowViewModel, that is the currently selected job, and you would bind to that:
Basically something like this:
And your MainWindowViewModel: