Validation on ObservableCollection

Mar 6, 2012 at 9:29 AM

Hello,

I have a window with a list as its only property:

 

ObservableCollection<Ingredient> IngredientList

 

The view enables editing of the current row (I add the code for others as reference if someone stumbles over this post)

 

    <ListView ItemsSource="{Binding IngredientList}">

        <ListView.View>

            <GridView AllowsColumnReorder="true" >

                <GridViewColumn DisplayMemberBinding="{Binding Path=Name}" Header="Ingredient" Width="Auto"/>
                <GridViewColumn Header="Danger" Width="Auto">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <Grid>
                                <TextBlock Text="{Binding Path=DangerClass}" Style="{StaticResource ListViewUnSelected}"/>
                                <TextBox Text="{Binding Path=DangerClass, ValidatesOnDataErrors=True, NotifyOnValidationError=True}" Style="{StaticResource ListViewSelected}" />
                            </Grid>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>

            </GridView>

        </ListView.View>
    </ListView>
  ...

    <Style x:Key="ListViewUnSelected" TargetType="{x:Type TextBlock}">
        <Setter Property="Visibility" Value="{Binding Path=IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=False}" />
    </Style>
    <Style x:Key="ListViewSelected" TargetType="{x:Type FrameworkElement}">
        <Setter Property="Visibility" Value="{Binding Path=IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=True}" />
    </Style>

I have some validation code in my Ingredient model. So if I enter a wrong value, the error is displayed nicely in the grid. Cool.

But the OK button of the dialog is not disabled. How should I best do this using the framework?

Thanks, Gorroux

 

 

 

Mar 6, 2012 at 10:40 AM
Edited Mar 6, 2012 at 10:43 AM

An additional question for this: The Textbox gets a red border on the error which is nice. But if I leave the row, it gets replaced by the label of course, which has no border then. There is still the error message at the top of the screen, but no indication as to in which row the error is.

Can I somehow link those controls or give the user another chance to see the error?

Is the EndEdit called after the user leaves the row? That would explain why the Cancel button does not work as I intended, as each row keeps its own state and is not handled over the collection.

Coordinator
Mar 6, 2012 at 5:10 PM

Good question. You can override the ValidateBusinessRules or ValidateFields and validate the collection yourself (but remember, this can be quite expensive). Another thing you can do is to put a WarningAndErrorValidator on your view like this (yes, it supports collections):

<WarningAndErrorValidator Source="{Binding IngredientList}" />

The InfoBarMessageControl that is available on the DataWindow will automatically check for WarningAndErrorValidator controls and use that as source for validation. The only downside of this approach is that the Validate on the view model will not return false (and thus the OK button will be enabled).

Developer
Mar 7, 2012 at 5:14 PM
Edited Mar 7, 2012 at 6:12 PM

You can use a validation framework, for instance FluentValidation, and  use it's capabilities in order to validate collections.

See: Custom Validators

See: Re-using Validators for Collections

Now Catel comes with it's own implementation of a provider to use FluentValidation.

See: Catel.Extensions.FluentValidation

It is available in beta version, so you can download it executing "Install-Package Catel.Extensions.FluentValidation –IncludePrerelease" in package manager console.

Mar 28, 2012 at 7:18 AM

Thanks for the idea with the fluent validation. I just made a quick try but it seems that it is only supported on the ViewModels, and not on the models directly. Why is this so? It would have been a real power if I have e.g. a model with model-based validation, and a ViewModel collection, with a fluent validation there.

PS: Most of your links point to the same page.

Developer
Mar 29, 2012 at 4:25 PM

1 - Sorry about the links. Actually I tried to fix it, but seems like the "fix" doesn't work.

The original post was:

"You can use a validation framework, for instance FluentValidation (http://fluentvalidation.codeplex.com/documentation), and  use it's capabilities in order to validate collections.

See: Custom Validators (http://fluentvalidation.codeplex.com/wikipage?title=Custom&referringTitle=Documentation)

See: Re-using Validators for Collections (http://fluentvalidation.codeplex.com/wikipage?title=CreatingAValidator&referringTitle=Documentation&ANCHOR#Collections)

Now Catel comes with it's own implementation of a provider to use FluentValidation (http://fluentvalidation.codeplex.com/documentation).

See: Catel.Extensions.FluentValidation (http://catel.catenalogic.com/3.0-beta/catel_extensions_fluentvalidat.htm)

It is available in beta version, so you can download it executing "Install-Package Catel.Extensions.FluentValidation –IncludePrerelease" in package manager console."

2 - Model-base validator.

I don't understand your issue. You can create a full validation of your models with FluentValidation and reuse it on the view-model validator.