Reputation: 12833
Using the code below I can trap an invalid cell entry. In this simple example of a grocery shopping list, the GroceryItem.Name
just needs to be filled in.
What I would like to do now is add the ability to validate that the entry doesn't already exist. If it does already exist then I'd like the same cell entry highlighted but with the appropriate message. So if the user enters "Eggs" again, the cell error message should be "Eggs is already on the list".
The item view model shouldn't know about it's container view model, so where can I check for a duplicate entry while still at cell validation for the "Name" property?
Item in the Collection
public class GroceryItem : ObservableObject, IDataErrorInfo
{
#region Properties
/// <summary>The name of the grocery item.</summary>
public string Name
{
get { return _name; }
set
{
_name = value;
RaisePropertyChangedEvent("Name");
}
}
private string _name;
#endregion
#region Implementation of IDataErrorInfo
public string this[string columnName] {
get {
if (columnName == "Name") {
if (string.IsNullOrEmpty(Name))
return "The name of the item to buy must be entered";
}
return string.Empty;
}
}
public string Error { get { ... } }
#endregion
}
View Model holding the Collection
public class MainWindowViewModel : ViewModelBase
{
/// <summary>A grocery list.</summary>
public ObservableCollection<GroceryItem> GroceryList
{
get { return _groceryList; }
set
{
_groceryList = value;
RaisePropertyChangedEvent("GroceryList");
}
}
private ObservableCollection<GroceryItem> _groceryList;
/// <summary>The currently-selected grocery item.</summary>
public GroceryItem SelectedItem { get; [UsedImplicitly] set; }
void OnGroceryListChanged(object sender, NotifyCollectionChangedEventArgs e)
{
// doing non-validation stuff
}
}
View Binding for DataGrid
<DataGrid
x:Name="MainGrid"
ItemsSource="{Binding GroceryList}"
SelectedItem="{Binding SelectedItem}"
...
>
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="TextBlock.ToolTip"
Value="{Binding Error}" />
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
...
<DataGridTextColumn Header="Item" Width="*" Binding="{Binding Name, ValidatesOnDataErrors=True}" IsReadOnly="false" />
</DataGrid.Columns>
</DataGrid>
Upvotes: 1
Views: 3612
Reputation: 45096
I don't know if this violates MVVM but the way I would do it is pass GroceryList to GroceryItem in another constructor and save it in a private ObservableCollection groceryList in GroceryItem. It is just a reverence back to GroceryList so it does not add a much overhead.
public class GroceryItem : ObservableObject, IDataErrorInfo
{
private ObservableCollection<GroceryItem> groceryList;
public void GroceryItem(string Name, ObservableCollection<GroceryItem> GroceryList)
{
name = Name;
groceryList = GroceryList;
// now you can use groceryList in validation
}
}
Upvotes: 1