Validating a ListBox's contents are not empty

Tony Vitabile

My .NET 4.0 WPF application has a dialog box which contains a ListBox. The ListBox is initially empty. The dialog has UI controls that allow the user to insert items into the ListBox. I'm using MVVM and the view model class implements IDataErrorInfo. There is an ObservableCollection in the view model class which is bound to the ListBox's ItemsSource property.

I don't want to let the user click OK until they've entered at least one item into the ListBox. If the ListBox is empty, I want to display a red border around it & an error icon to the right of it, with the error message in the ListBox's tooltip. This is the way all other errors are displayed in my application.

Here's an edited version of the XAML:

<Window x:Class="MyDialog class's type"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:cs="clr-namespace:MyControlsDLL's namespace"
        xmlns:vm="clr-namespace:My View Model DLL's namespace"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        mc:Ignorable="d"
        DataContext="{Binding Path=SelectedCamera, RelativeSource={RelativeSource Self}}"
        Loaded="MyDialog_Loaded"
        SizeToContent="Height"
        cs:ThemeSelector.CurrentThemeDictionary="{Binding Path=TimeOfDayTheme, RelativeSource={RelativeSource Self}}"
        Width="800"
        WindowStartupLocation="CenterOwner">

    <cs:MyDialog.CommandBindings>
        <cs:DataContextCommandBinding CanExecute="CanAddOrEditItem" Command="cs:MyCommands.AddItem"    Executed="AddOrEditItem" />
        <cs:DataContextCommandBinding CanExecute="CanRemoveItem"    Command="cs:MyCommands.RemoveItem" Executed="RemoveItem" />
    </cs:MyDialog.CommandBindings>

    <cs:MyDialog.Resources>
        <ResourceDictionary>
            <BitmapImage x:Key="ErrorImage" UriSource="Resources/Error.png" />

            <cs:BooleanInverter              x:Key="NOT" />
            <cs:BooleanToVisibilityConverter x:Key="BoolToVisibile"  True="Visible"   False="Collapsed" />
            <cs:BooleanToVisibilityConverter x:Key="BoolToCollapsed" True="Collapsed" False="Visible" />
            <cs:EnumToBooleanConverter       x:Key="SubTypeConverter" />
            <cs:MultiBoolConverter           x:Key="BoolCombiner" />

            <cs:EnumDisplayer ResourceManager="{x:Static res:MyApp.ResourceManager}" Type="{x:Type sys:DateTimeKind}" x:Key="DateTimeKinds">
                <cs:EnumOverride EnumValue="Local"       ResourceKey="DateKind_Local" />
                <cs:EnumOverride EnumValue="Unspecified" ResourceKey="DateKind_Unspecified" />
                <cs:EnumOverride EnumValue="Utc"         ResourceKey="DateKind_Utc" />
            </cs:EnumDisplayer>

            <cs:EnumDisplayer ResourceManager="{x:Static res:MyApp.ResourceManager}" Type="{x:Type vm:MyTypes}" x:Key="MyTypes" />

            <ControlTemplate x:Key="InputErrorTemplate">
                <DockPanel LastChildFill="True">
                    <Image DockPanel.Dock="Right"
                            Height="20"
                            Margin="-30,0,0,0"
                            Source="{StaticResource ErrorImage}"
                            ToolTip="{x:Static res:MyApp.Common_InvalidData}"
                            VerticalAlignment="Center"
                            Width="20" />
                    <Border BorderBrush="Red"
                            BorderThickness="5"
                            Margin="5,5,30,5">
                        <AdornedElementPlaceholder />
                    </Border>
                </DockPanel>
            </ControlTemplate>

            <Style TargetType="{x:Type ListBox}">
                <Setter Property="Validation.ErrorTemplate" Value="{StaticResource InputErrorTemplate}" />
                <Style.Triggers>
                    <Trigger Property="Validation.HasError" Value="True">
                        <Setter Property="ToolTip">
                            <Setter.Value>
                                <Binding Path="(Validation.Errors).CurrentItem.ErrorContent" RelativeSource="{x:Static RelativeSource.Self}" />
                            </Setter.Value>
                        </Setter>
                    </Trigger>
                </Style.Triggers>
            </Style>

            <Style TargetType="{x:Type TextBox}">
                <Setter Property="Validation.ErrorTemplate" Value="{StaticResource InputErrorTemplate}" />
                <Style.Triggers>
                    <Trigger Property="Validation.HasError" Value="True">
                        <Setter Property="ToolTip">
                            <Setter.Value>
                                <Binding Path="(Validation.Errors).CurrentItem.ErrorContent" RelativeSource="{x:Static RelativeSource.Self}" />
                            </Setter.Value>
                        </Setter>
                    </Trigger>
                </Style.Triggers>
            </Style>
        </ResourceDictionary>
    </cs:MyDialog.Resources>

    <Grid Name="LayoutRoot" Grid.IsSharedSizeScope="True">
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <AdornerDecorator Grid.Row="0">
            <Grid Name="CommonRoot">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto" SharedSizeGroup="Column1" />
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="5" />
                    <ColumnDefinition Width="Auto" SharedSizeGroup="Column2" />
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="5" />
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>

                <TextBlock Grid.Column="0"
                           Grid.Row="0"
                           Margin="5"
                           Text="Name:"
                           TextAlignment="Right"
                           VerticalAlignment="Center" />
                <TextBox Grid.Column="1"
                         Grid.Row="0"
                         Margin="5,5,30,5"
                         MaxLength="50"
                         Name="NameBox"
                         TabIndex="0"
                         Text="{Binding Mode=TwoWay, NotifyOnSourceUpdated=True, Path=Name, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
                         TextAlignment="Left"
                         VerticalAlignment="Center" />

                <TextBlock Grid.Column="3"
                           Grid.Row="0"
                           Margin="5"
                           Text="Type:"
                           TextAlignment="Right"
                           VerticalAlignment="Center" />
                <ComboBox Grid.Column="4"
                          Grid.Row="0"
                          Height="50"
                          ItemsSource="{Binding Source={StaticResource MyTypes}, Path=DisplayNames}"
                          SelectedValue="{Binding Converter={StaticResource MyTypes}, Mode=TwoWay, Path=MyType}"
                          SelectionChanged="LPRTypePicker_SelectionChanged"
                          Margin="5"
                          x:Name="MyTypePicker"
                          TabIndex="1"
                          VerticalAlignment="Center" />

                <TabControl Grid.Column="0"
                            Grid.ColumnSpan="6"
                            Grid.Row="1"
                            Name="Tabs">

                    <TabItem Header="Tab 1"
                             Name="Tab1">
                        <AdornerDecorator>
                            <Border BorderBrush="{DynamicResource ELDControlBorder}"
                                    BorderThickness="0,0,0,1">
                                <Grid Background="{DynamicResource ELDContentBackground}"
                                      Name="LPRConfiguration">
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="Auto" SharedSizeGroup="Column1" />
                                        <ColumnDefinition Width="*" />
                                        <ColumnDefinition Width="5" />
                                        <ColumnDefinition Width="Auto" SharedSizeGroup="Column2" />
                                        <ColumnDefinition Width="*" />
                                        <ColumnDefinition Width="5" />
                                    </Grid.ColumnDefinitions>
                                    <Grid.RowDefinitions>
                                        <!-- Row definitions -->
                                    </Grid.RowDefinitions>

                                    <!-- Controls for this TabItem -->
                                </Grid>
                            </Border>
                        </AdornerDecorator>
                    </TabItem>

                    <TabItem Header="Directories List"
                             Visibility="{Binding Path=CanShow, Converter={StaticResource BoolToVisibile}}">
                        <AdornerDecorator>
                            <Border BorderThickness="0,0,0,1">
                                <Grid Name="Tab2Root">
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="150" SharedSizeGroup="Column1" />
                                        <ColumnDefinition Width="3.5*" />
                                        <ColumnDefinition Width="110" />
                                    </Grid.ColumnDefinitions>
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="Auto" />
                                        <RowDefinition Height="Auto" />
                                        <RowDefinition Height="Auto" />
                                        <RowDefinition Height="Auto" />
                                        <RowDefinition Height="Auto" />
                                    </Grid.RowDefinitions>

                                    <TextBlock Grid.Column="0"
                                               Grid.Row="0"
                                               HorizontalAlignment="Right"
                                               Margin="5"
                                               Text="Mode:" />

                                    <Grid Grid.Column="1"
                                          Grid.ColumnSpan="2"
                                          Grid.Row="0">
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition Width="1*" />
                                            <ColumnDefinition Width="2*" />
                                            <ColumnDefinition Width="1*" />
                                            <ColumnDefinition Width="2*" />
                                            <ColumnDefinition Width="1*" />
                                        </Grid.ColumnDefinitions>

                                        <RadioButton Content="SubType 1"
                                                     Grid.Column="1"
                                                     GroupName="SubTypes"
                                                     IsChecked="{Binding Converter={StaticResource SubTypeConverter}, ConverterParameter=SubType1, Path=SubType}"
                                                     Margin="5"
                                                     TabIndex="8"
                                                     VerticalAlignment="Center" />
                                        <RadioButton Checked="SubType_Changed" 
                                                     Content="Value2"
                                                     Grid.Column="3"
                                                     GroupName="SubTypes"
                                                     IsChecked="{Binding Converter={StaticResource SubTypeConverter}, ConverterParameter=SubType2, Path=SubType}"
                                                     Margin="5"
                                                     Name="SubTypeSubType2Button"
                                                     TabIndex="8"
                                                     VerticalAlignment="Center" />
                                    </Grid>

                                    <TextBlock Grid.Column="0"
                                               Grid.Row="2"
                                               HorizontalAlignment="Right"
                                               Margin="5"
                                               Text="An Item:"
                                               VerticalAlignment="Center"
                                               Visibility="{Binding Converter={StaticResource BoolToVisibile}, Path=SubTypeIsSubType1}" />

                                    <Grid Grid.Column="1"
                                          Grid.Row="2"
                                          Visibility="{Binding Converter={StaticResource BoolToVisibile}, Path=SubTypeIsSubType1}">
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition Width="*" />
                                            <ColumnDefinition Width="Auto" />
                                        </Grid.ColumnDefinitions>

                                        <TextBox Grid.Column="0"
                                                 Margin="5"
                                                 Name="NewItemBox"
                                                 TabIndex="11"
                                                 Text="{Binding Mode=TwoWay, Path=NewItem, UpdateSourceTrigger=PropertyChanged}"
                                                 ToolTip="{x:Static res:MyApp.MyDialog_NewItem_Tooltip}"
                                                 VerticalAlignment="Center" />

                                        <Button Command="cs:MyCommands.Browse"
                                                Content="Browse..."
                                                Grid.Column="1"
                                                Height="35"
                                                Margin="5"
                                                Name="BrowseDirectoriesButton"
                                                TabIndex="12" />
                                    </Grid>

                                    <Button Command="cs:MyCommands.AddItem"
                                            Content="{Binding Path=AddOrEditLabel}"
                                            Grid.Column="2"
                                            Grid.Row="2"
                                            Height="50"
                                            Margin="5"
                                            Name="AddItemButton"
                                            TabIndex="13" />

                                    <TextBlock Grid.Column="0"
                                               Grid.Row="3"
                                               HorizontalAlignment="Right"
                                               Margin="5"
                                               Text="Selected Items:"
                                               TextAlignment="Right"
                                               TextWrapping="WrapWithOverflow"
                                               Visibility="{Binding Converter={StaticResource BoolToVisibile}, Path=SubTypeIsSubType1}" />

                                    <ListBox Grid.Column="1"
                                             Grid.Row="3"
                                             Height="160"
                                             ItemsSource="{Binding Path=SelectedItems}"
                                             Margin="5,5,30,5"
                                             Name="ItemsList"
                                             SelectedValue="{Binding Mode=TwoWay, Path=SelectedItem, ValidatesOnDataErrors=True}"
                                             TabIndex="14"
                                             Visibility="{Binding Converter={StaticResource BoolToVisibile}, Path=SubTypeIsSubType1}" />

                                    <Button Command="cs:MyCommands.RemoveItem"
                                            Content="Remove"
                                            Grid.Column="2"
                                            Grid.Row="3"
                                            Height="50"
                                            Margin="5"
                                            Name="RemoveItemButton"
                                            TabIndex="15"
                                            VerticalAlignment="Top"
                                            Visibility="{Binding Converter={StaticResource BoolToVisibile}, Path=SubTypeIsSubType1}" />
                                </Grid>
                            </Border>
                        </AdornerDecorator>
                    </TabItem>
                </TabControl>
            </Grid>
        </AdornerDecorator>

        <!-- OK & Cancel Buttons here -->
    </Grid>
</Window>

There's a complication in here in that even though this ListBox is initially empty, it's only an error for it to be empty if the Type property is one value & the SubType property is SubType1. Initially, those properties do not have those values. When the dialog is first displayed, I can see my validation code getting called, but no error is displayed because the ListBox isn't even being displayed.

After I change the Type property, the SubType property is automatically set to SubType1 & the ListBox is displayed and it is empty. I've been able to verify that the validation code in my View Model class's IDataErrorInfo implementation is being called, and an error message is returned, but no error template is displaying. Actually, no errors are being displayed on that tab at all, and I think it's identical to the tab before it, which is displaying errors.

What did I do wrong with the ListBox?

EDIT

There is a TextBox on that Tab that also is initially in an error state & no error message was being displayed. When I put some text in it, the validation code ran & it was marked OK. When I emptied it, however, it did show an error condition. Maybe my problem is that I need to do something to put it into an error state when the user chooses Type1 or changes the SubType?

Tony Vitabile

I got it to work. I added ValidatesOnDataErrors=True to the binding for the ItemsSource property on the ListBox and now the error template is displaying.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

Validating a ListBox's contents are not empty

From Dev

Validating if a combobox it's SelectedText property is empty always fails

From Dev

Validating TinyMCE for empty inputs

From Dev

Validating empty $_FILES

From Dev

Validating TinyMCE for empty inputs

From Dev

clojure spec - validating contents of maps

From Dev

Sorting contents of a listbox

From Dev

empty() check not validating after POST

From Dev

Jquery validating not empty and is URL in forms

From Dev

Listbox with multiple columns of the same contents

From Dev

Best way to stretch WPF ListBox.ItemTemplate's contents to the width of ListBoxItem

From Dev

Best way to stretch WPF ListBox.ItemTemplate's contents to the width of ListBoxItem

From Dev

How to check if listbox is empty?

From Dev

remove empty fields in a listbox

From Dev

How to check if listbox is empty?

From Dev

validating file contents when uploading to Django form

From Dev

validating file contents when uploading to Django form

From Dev

Empty contents in contenteditable div

From Dev

Empty contents in contenteditable div

From Dev

How to get a listbox to return it's results into the next empty row in excel vba

From Dev

Listbox returning empty string? PHP

From Dev

Validating a string for a positive number, null/empty string

From Dev

Validating Null and Empty Strings using Jersey

From Dev

How to disable validating empty fields with bootstrapvalidator?

From Dev

Validating Null and Empty Strings using Jersey

From Dev

Sequalize validating email, fails with Empty String

From Dev

Vertically aligning the contents of a ListBox in a Windows Store app

From Dev

EASY: vba: Looking through a listbox and selecting the contents

From Dev

Need help looping through contents of a ListBox

Related Related

  1. 1

    Validating a ListBox's contents are not empty

  2. 2

    Validating if a combobox it's SelectedText property is empty always fails

  3. 3

    Validating TinyMCE for empty inputs

  4. 4

    Validating empty $_FILES

  5. 5

    Validating TinyMCE for empty inputs

  6. 6

    clojure spec - validating contents of maps

  7. 7

    Sorting contents of a listbox

  8. 8

    empty() check not validating after POST

  9. 9

    Jquery validating not empty and is URL in forms

  10. 10

    Listbox with multiple columns of the same contents

  11. 11

    Best way to stretch WPF ListBox.ItemTemplate's contents to the width of ListBoxItem

  12. 12

    Best way to stretch WPF ListBox.ItemTemplate's contents to the width of ListBoxItem

  13. 13

    How to check if listbox is empty?

  14. 14

    remove empty fields in a listbox

  15. 15

    How to check if listbox is empty?

  16. 16

    validating file contents when uploading to Django form

  17. 17

    validating file contents when uploading to Django form

  18. 18

    Empty contents in contenteditable div

  19. 19

    Empty contents in contenteditable div

  20. 20

    How to get a listbox to return it's results into the next empty row in excel vba

  21. 21

    Listbox returning empty string? PHP

  22. 22

    Validating a string for a positive number, null/empty string

  23. 23

    Validating Null and Empty Strings using Jersey

  24. 24

    How to disable validating empty fields with bootstrapvalidator?

  25. 25

    Validating Null and Empty Strings using Jersey

  26. 26

    Sequalize validating email, fails with Empty String

  27. 27

    Vertically aligning the contents of a ListBox in a Windows Store app

  28. 28

    EASY: vba: Looking through a listbox and selecting the contents

  29. 29

    Need help looping through contents of a ListBox

HotTag

Archive