验证ListBox的内容不为空

时间:2014-08-08 19:02:43

标签: c# wpf xaml mvvm listbox

我的.NET 4.0 WPF应用程序有一个包含ListBox的对话框。 ListBox最初为空。该对话框具有UI控件,允许用户将项目插入ListBox。我正在使用MVVM,视图模型类实现IDataErrorInfo。视图模型类中有ObservableCollection绑定到ListBox's ItemsSource属性。

我不想让用户点击确定,直到他们在ListBox中输入至少一个项目为止。如果ListBox为空,我想在其周围显示红色边框&右侧的错误图标,ListBox's工具提示中显示错误消息。这是我的应用程序中显示所有其他错误的方式。

以下是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>

这里有一个复杂的问题,即使这个ListBox最初是空的,如果Type属性是一个值&amp;,它只是一个错误。 SubType属性是SubType1。最初,这些属性没有这些值。首次显示对话框时,我可以看到我的验证代码被调用,但没有显示错误,因为甚至没有显示ListBox

更改Type属性后,SubType属性自动设置为SubType1&amp;显示ListBox,它为空。我已经能够验证我的View Model类的IDataErrorInfo实现中的验证代码是否被调用,并返回错误消息,但没有显示错误模板。实际上,该标签上根本没有显示任何错误,我认为它与之前的标签相同,显示错误。

我对ListBox做错了什么?

修改

TextBox上的Tab最初也处于错误状态&amp;没有显示错误消息。当我在其中放入一些文本时,验证代码运行&amp;它被标记为OK。然而,当我清空它时,确实显示出错误状态。也许我的问题是,当用户选择Type1或更改SubType时,我需要做一些事情才能将其置于错误状态?

1 个答案:

答案 0 :(得分:1)

我得到了它的工作。我将ValidatesOnDataErrors=True添加到ItemsSourceListBox属性的绑定中,现在显示错误模板。