Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Validating items in ItemsControl

Tags:

c#

wpf

xaml

I am developing a WPF application and in one window I used a wizard component from WPF toolkit. In this wizard I'm creating a new person. In second step I am using an enumeration as a source for possible contact types (for example Phone, Email...).

This is my wizard page in XAML:

<xctk:WizardPage x:Name="NewContactPage" PageType="Interior"
                Title="Contacts" Style="{DynamicResource NewContactPage}"
                CanCancel="True" CanFinish="False"
                Loaded="NewContactPage_Loaded" 
                PreviousPage="{Binding ElementName=NewPersonPage}">
    <Grid HorizontalAlignment="Stretch" VerticalAlignment="Top">
        <control:DataLoader x:Name="ctrNewContactLoader" />
        <StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Top" Orientation="Vertical">
            <ItemsControl ItemsSource="{Binding Path=Person.PersonContacts, Mode=TwoWay,
                                                            RelativeSource={RelativeSource Mode=FindAncestor,
                                                                                           AncestorType=Window}}"
                                      Name="icContacts">
                <ItemsControl.ItemTemplate>
                    <ItemContainerTemplate>
                        <StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Top" Orientation="Vertical"


                        Margin="5" Background="WhiteSmoke">
                        <CheckBox IsChecked="{Binding Path=IsValid}" 
                                              Content="{Binding Path=ContactType.Description}"
                                              Name="cbContactVisible"/>

                        <Grid HorizontalAlignment="Stretch" VerticalAlignment="Top"
                                          Visibility="{Binding ElementName=cbContactVisible, Path=IsChecked, 
                                                               Converter={StaticResource BooleanToVisibilityConverter}}">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="*" />
                            </Grid.ColumnDefinitions>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="auto" />
                            </Grid.RowDefinitions>

                            <TextBox Grid.Row="0" Grid.Column="0"
                                                 HorizontalAlignment="Stretch" MaxLength="64"
                                                 Name="txtContactValue"
                                                 Text="{Binding Path=Contact,
                                                        ValidatesOnDataErrors=True,
                                                        ValidatesOnNotifyDataErrors=True,
                                                        ValidatesOnExceptions=True}" />
                        </Grid>
                    </StackPanel>
                </ItemContainerTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </StackPanel>
</Grid>

The source of ItemsControl is a List of PersonContactModel class:

public class PersonContactModel : BaseObjectModel
{
    public PersonContactModel()
    {
        this.Created = DateTime.Now;
        this.Updated = DateTime.Now;

        this.IsValid = true;

        this.ContactType = new ContactTypeModel();
    }

    public string Contact { get; set; }
    public ContactTypeModel ContactType { get; set; }
    public DateTime Created { get; set; }

    public int Id { get; set; }
    public bool IsValid { get; set; }
    public DateTime Updated { get; set; }

    public override string this[string columnName]
    {
        get
        {
            string retVal = string.Empty;
            switch (columnName)
            {
                case "Contact":
                    retVal = base.Concat(base.RequeiredField(this.Contact), base.MinLength(this.Contact, 5), base.MaxLength(this.Contact, 62));
                    break;
            }

            return retVal;
        }
    }
} 

the base class implement a IDataErrorInfo interface with validation info about Contact property.

The desired behavior is that if the checkbox is checked, it is visible grid with a field for entering a contact, otherwise not. Button next step should be seen only when selected contact types are valid. This functionality is trying to accomplish the following styles in app.xaml:

<Style TargetType="xctk:WizardPage" x:Key="NewContactPage">
    <Setter Property="NextButtonVisibility" Value="Hidden" />
    <Style.Triggers>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding Path=(Validation.HasError), ElementName=txtContactValue}" Value="False" />
            </MultiDataTrigger.Conditions>
            <Setter Property="NextButtonVisibility" Value="Visible" />
        </MultiDataTrigger>
    </Style.Triggers>
</Style>

Unfortunately, the button for the next step is invisible, even if it asks all kinds of contact for the new person and will fulfill all the conditions for a valid entry.

What's wrong? Where is an error?

like image 380
Davecz Avatar asked Sep 12 '15 15:09

Davecz


1 Answers

You are trying to achieve what you want in a not very good way. Error in this particular code is because you reference element "txtContactValue" from your style trigger, and style has no idea at all what this element is. By the way, if you look at output window when debugging your code, I bet you will see this error there.

Now, even if you will try to reference "txtContactValue" without style, like this:

NextButtonVisibility="{Binding ElementName=txtContactValue, Path=(Validation.HasError), Converter={StaticResource BooleanToVisibilitConverter}}"

It won't work, because txtContactValue is in different scope. BUT you should not do this in a first place! You have a model for your data, and that is model which controls if data is valid or not. Just add some property to your model which indicates if data which you create on this wizard page is valid (like PersonContact.IsValid) and you can proceed to the next page, and bind to this property.

like image 105
Evk Avatar answered Sep 30 '22 22:09

Evk