Bagaimana cara memvalidasi ListBox (MVVM)?

Saya harap saya dapat menjelaskan kode dan masalah saya dengan baik, karena kodenya banyak. Kami sedang membuat Aplikasi Pengelola Buku di Visual Studio. Model (Book.cs) berisi properti buku (Penulis, Judul, Rilis, dll).

Di MainWindow.xaml kita memiliki ListBox dengan semua buku terdaftar dan di sisi kiri ada Label dan TextBox yang sesuai dengan Properties (Label "Penulis" dan di TextBox muncul nama Penulis). Dengan kotak teks ini Anda dapat memperbarui properti. Begitu pula tampilan xamlnya sejauh ini:

<Window x:Class="BookApplication.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:model="clr-namespace:BookApplication.Model"
        xmlns:viewModel="clr-namespace:BookApplication.ViewModel"
        mc:Ignorable="d"
        Title="Book-Manager" Height="350" Width="525">
    <Window.Resources>
        <model:Book x:Key="myBook" Title="Harry Potter und die Heiligtümer des Todes" Author="J.K.Rowling" Publisher="Carlsen" Edition="1" Release="01.01.2017" ></model:Book>
        <viewModel:BookCollectionViewModel x:Key="bcvm"></viewModel:BookCollectionViewModel>

    </Window.Resources>


    <DockPanel>
        <Menu DockPanel.Dock="Top">
            <MenuItem Header="Datei">
                <MenuItem Header="Neu" Command="{Binding NewClick, Mode=OneWay, Source={StaticResource bcvm}}" InputGestureText="Strg+N"/>
                <Separator/>
                <MenuItem x:Name="Open" Header="Öffnen" Command="{Binding LoadClick, Mode=OneWay, Source={StaticResource bcvm}}" InputGestureText="Strg+O"/>
                <MenuItem x:Name="Save" Header="Speichern" Command="{Binding SaveClick, Mode=OneWay, Source={StaticResource bcvm}}" InputGestureText="Strg+S"/>
                <MenuItem Header="Speichern unter..." Command="{Binding SaveAsClick, Mode=OneWay, Source={StaticResource bcvm}}"/>

            </MenuItem>
            <MenuItem Header="Neues Buch" Command="{Binding NewBookClick, Mode=OneWay, Source={StaticResource bcvm}}"></MenuItem>
        </Menu>


        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="252*"/>
                <ColumnDefinition Width="265*"/>
            </Grid.ColumnDefinitions>

            <Grid Grid.Column="0" Margin="-2,0,0,0">
                <Label x:Name="labelTitle" Content="Titel" HorizontalAlignment="Left" Margin="9,10,0,0" VerticalAlignment="Top" Width="46" Height="20" FontSize="8"/>
                <TextBox x:Name="textboxTitle" HorizontalAlignment="Left" Height="20" Margin="87,10,0,0" TextWrapping="Wrap" Text="{Binding ElementName= BooksListBox, Path=SelectedItem.Title}" VerticalAlignment="Top" Width="160" FontSize="8" />

                <Label x:Name="labelAuthor" Content="Autor" HorizontalAlignment="Left" Margin="10,30,0,0" VerticalAlignment="Top" Width="62" Height="22" FontSize="8"/>
                <TextBox x:Name="textboxAuthor" HorizontalAlignment="Left" Height="18" Margin="87,34,0,0" TextWrapping="Wrap"  Text="{Binding ElementName=BooksListBox, Path=SelectedItem.Author}" VerticalAlignment="Top" Width="160" FontSize="8" />

                <Label x:Name="labelPublisher" Content="Verlag" HorizontalAlignment="Left" Margin="10,52,0,0" VerticalAlignment="Top" Width="45" FontSize="8" Height="24"/>
                <TextBox x:Name="textboxPublisher" HorizontalAlignment="Left" Height="17" Margin="87,58,0,0" TextWrapping="Wrap" Text="{Binding Source={StaticResource myBook}, Path=Publisher, Mode=TwoWay}" VerticalAlignment="Top" Width="160" FontSize="8" />

                <Label x:Name="labelEdition" Content="Auflage" HorizontalAlignment="Left" Margin="10,76,0,0" VerticalAlignment="Top" Width="45" FontSize="8" Height="26"/>
                <TextBox x:Name="textboxEdition" HorizontalAlignment="Left" Height="15" Margin="87,79,0,0" TextWrapping="Wrap" Text="{Binding ElementName=BooksListBox, Path=SelectedItem.Edition}" VerticalAlignment="Top" Width="160" FontSize="8" />

                <Label x:Name="labelRelease" Content="Veröffentlichung" HorizontalAlignment="Left" Margin="9,99,0,0" VerticalAlignment="Top" Width="102" FontSize="8"/>
                <TextBox x:Name="textboxRelease" HorizontalAlignment="Left" Height="14" Margin="87,103,0,0" TextWrapping="Wrap" Text="{Binding ElementName=BooksListBox, Path=SelectedItem.Release, Mode=TwoWay}" VerticalAlignment="Top" Width="160" FontSize="8" />

                <Label x:Name="labelISBN" Content="ISBN" HorizontalAlignment="Left" Margin="9,120,0,0" VerticalAlignment="Top" Width="81" FontSize="8"/>
                <TextBox x:Name="textboxISBN" HorizontalAlignment="Left" Height="14" Margin="87,125,0,0" TextWrapping="Wrap" Text="{Binding ElementName=BooksListBox, Path=SelectedItem.Isbn}" VerticalAlignment="Top" Width="160" FontSize="8" />

                <Button x:Name="buttonRemove" Command="{Binding RemoveBookClick, Mode=OneWay, Source={StaticResource bcvm}}" Content="Löschen" HorizontalAlignment="Left" Margin="9,160,0,0" VerticalAlignment="Top" Width="75"/>
            </Grid>

            <ListBox Grid.Column="1" x:Name="BooksListBox" ItemsSource="{Binding Source={StaticResource bcvm}}" SelectedItem="{Binding Source={StaticResource bcvm}, Path=SelectedBook}">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel>
                            <TextBlock FontWeight="Bold" FontSize="12" Text="{Binding Path=Title}"/>
                            <StackPanel Orientation="Horizontal">
                                <TextBlock Text="{Binding Path=Author}"></TextBlock>
                                <TextBlock Text=";  Auflage: "></TextBlock>
                                <TextBlock Text="{Binding Path=Edition}"></TextBlock>
                            </StackPanel>
                            <Canvas Width="50" Height="12" HorizontalAlignment="Left" >
                                <Ellipse Name="LeftEllipse" Height="10" Stroke="Black" Fill="{Binding Path=ColorLeft}" Width="10" Canvas.Left="10"/>
                                <Ellipse Name="MiddleEllipse" Height="10" Stroke="Black" Fill="{Binding Path=ColorMiddle}" Width="10" Canvas.Left="30"/>
                                <Ellipse Name="RightEllipse" Height="10" Stroke="Black" Fill="{Binding Path=ColorRight}" Width="10" Canvas.Left="50"/>
                            </Canvas>
                        </StackPanel>

                    </DataTemplate>
                </ListBox.ItemTemplate>

            </ListBox>

        </Grid>
    </DockPanel>

</Window>

Jika Anda mengklik buku mana pun dalam daftar, nilai Properti akan berada di Kotak Teks kiri, dan ini dapat Anda edit, seperti yang saya katakan.

Sekarang saya harus melakukan validasi. Masalahnya adalah, saya hanya dapat menemukan validasi langsung dari properti, dan saya ingin memvalidasi nilai dan nilai yang diperbarui dari ListBox.

Saya sudah mencoba melakukan sesuatu seperti ini (sumber : https://msdn.microsoft.com/es-es/library/ms753962, sumbernya tidak dalam bahasa Inggris, tetapi kodenya cukup jelas).

Saya membuat kelas AuthorRule yang terlihat seperti ini:

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;

namespace BookApplication.Model.Validation
{
    class AuthorRule : ValidationRule
    {
        public AuthorRule()
        {

        }

        public override ValidationResult Validate(object value, CultureInfo cultureInfo)
        {

           if (String.IsNullOrWhiteSpace((String)value))
           {
                return new ValidationResult(false, "Dieser Feld ist verpflichtend.");
            }
            else
            {
                return new ValidationResult(true, null);
            }

        }
    }
}

sekedar untuk pembuktian, jika Field tersebut kosong. Model atau Book.cs saya belum diubah. MainWindow.xaml saya terlihat seperti ini (seperti potongan kode lainnya, tetapi saya hanya akan menampilkan perubahan di WindowResources dan di Kotak Teks "Penulis"):

<Window.Resources>
        <model:Book x:Key="myBook" Title="Harry Potter und die Heiligtümer des Todes" Author="J.K.Rowling" Publisher="Carlsen" Edition="1" Release="01.01.2017" ></model:Book>
        <viewModel:BookCollectionViewModel x:Key="bcvm"></viewModel:BookCollectionViewModel>

        <ControlTemplate x:Key="validationTemplate">
            <DockPanel>
                <TextBlock Foreground="Red" FontSize="20">
                    <Run Text="!" />
                </TextBlock>
            </DockPanel>
        </ControlTemplate>

        <Style x:Key="textBoxInError" TargetType="{x:Type TextBox}">
            <Style.Triggers>
                <Trigger Property="Validation.HasError" Value="true">
                    <Setter Property="ToolTip" Value="{Binding (Validation.Errors)[0].ErrorContent, RelativeSource={x:Static RelativeSource.Self}}" />
                </Trigger>
            </Style.Triggers>

        </Style>

    </Window.Resources>

masukkan deskripsi gambar di sini

Gambar di atas adalah screenshot dari TextBox "Author". Saya tidak tahu harusnya path dan sourcenya apa, biar ListBoxnya tetap nyambung!!

Saya minta maaf atas pertanyaan yang panjang, adakah yang bisa membantu saya?


person bonishadelnorte    schedule 18.01.2018    source sumber


Jawaban (1)


Anda telah mengatur properti Teks di baris pertama dan Anda mengaturnya kembali di node TextBox.Text. Anda mungkin harus menghapus atribut Teks dan nilainya terlebih dahulu. Selain itu, bidang Sumber tidak diperlukan. Solusi akhir untuk TextBox seharusnya seperti ini.

<TextBox x:Name="textboxAuthor" HorizontalAlignment="Left" Height="18" Margin="87,34,0,0" TextWrapping="Wrap"  VerticalAlignment="Top" Width="160" FontSize="8" Validation.ErrorTemplate="{StaticResource validationTemplate}" Style="{StaticResource textBoxInError}">
                    <TextBox.Text>
                        <Binding Path="SelectedItem.Author" ElementName="BooksListBox" UpdateSourceTrigger="PropertyChanged">
                            <Binding.ValidationRules>
                                <validation:AuthorRule/>
                            </Binding.ValidationRules>
                        </Binding>
                    </TextBox.Text>
                </TextBox>

Ini seharusnya berhasil.

person Rajesh Gupta    schedule 18.01.2018