ItemsControl in RadDataForm: dynamic data form fields and validation

6 posts, 0 answers
  1. Johannes
    Johannes avatar
    66 posts
    Member since:
    Dec 2012

    Posted 06 Feb 2015 Link to this post

    I have to create some dynamic data fields inside RadDataForm so I've added an ItemsControl inside my RadDataForm. Please see code below for example. Everything works fine. A custom DataTemplateSelector checks a property called Value. If Value is of type string ItemsControl is using DataFormDataField template to display it with a TextBox. If Value is of type datetime ItemsControl is using DataFormDateField template to display it with a RadDatePicker. That's great but I'm having trouble with validation. I use Item level attribute-based validation as described in your documentation. This works perfect on usual data fields like the two shown below (ID and Name). But validation is not executed on my bound properties inside those mentioned DataTemplates. Inside every DataTemplate there is a DataBinding to property Value of my ViewModel. Just like ID and Name, Value also has Item level attribute-based validation ([Required(AllowEmptyStrings = false)]). When ID or Name are empty validation comes into place and I can not commit RadDataForm until I enter some text. That's what I want for my Value property, too. I hope this is understandable.


    <!-- ID -->
    <t:DataFormDataField Label="ID" Description="Todo" DataMemberBinding="{Binding ID, Mode=OneWay}">
        <t:DataFormDataField.Content>
            <t:RadWatermarkTextBox Text="{Binding ID, Mode=OneWay}" IsReadOnly="True" />
        </t:DataFormDataField.Content>
    </t:DataFormDataField>
    <!-- Name -->
    <t:DataFormDataField Label="Name" Description="Todo" DataMemberBinding="{Binding Name, Mode=TwoWay, NotifyOnValidationError=True}">
        <t:DataFormDataField.Content>
            <t:RadWatermarkTextBox Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" WatermarkContent="Please fill in your name" />
        </t:DataFormDataField.Content>
    </t:DataFormDataField>
    <!-- DYNAMIC DATA FIELDS -->
    <ItemsControl ItemsSource="{Binding Source={StaticResource CollectionViewSource}}" Focusable="False">
        <ItemsControl.ItemTemplateSelector>
            <v:MyDataTemplateSelector>
                <!-- Text DataTemplate (Value is string so show it in DataFormDataField) -->
                <v:MyDataTemplateSelector.TextBoxDataTemplate>
                    <DataTemplate>
                        <t:DataFormDataField Label="{Binding Label, Mode=OneWay}" Description="{Binding ToolTip, Mode=OneWay}" DataMemberBinding="{Binding Value, Mode=TwoWay, NotifyOnValidationError=True}">
                            <t:DataFormDataField.Content>
                                <t:RadWatermarkTextBox Text="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" WatermarkContent="Please insert value" />
                            </t:DataFormDataField.Content>
                        </t:DataFormDataField>
                    </DataTemplate>
                </v:MyDataTemplateSelector.TextBoxDataTemplate>
                <!-- Date DataTemplate (Value is datetime so show it as DataFormDateField) -->
                <v:MyDataTemplateSelector.DateDataTemplate>
                    <DataTemplate>
                        <t:DataFormDateField Label="{Binding Label, Mode=OneWay}" Description="{Binding ToolTip, Mode=OneWay}" DataMemberBinding="{Binding Value, Mode=TwoWay, NotifyOnValidationError=True}">
                            <t:DataFormDateField.Content>
                                <t:RadDatePicker DateSelectionMode="Year" SelectedValue="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
                            </t:DataFormDateField.Content>
                        </t:DataFormDateField>
                    </DataTemplate>
                </v:MyDataTemplateSelector.DateDataTemplate>
                <!-- More DataTemplates here ... -->
            </v:MyDataTemplateSelector>
        </ItemsControl.ItemTemplateSelector>
    </ItemsControl>


    Can you help me on this? I don't know what I am doing wrong here. It seems my validation rules/data annotations are just not recognized by RadDataForm when the binding is inside a DataTemplate.
  2. Johannes
    Johannes avatar
    66 posts
    Member since:
    Dec 2012

    Posted 06 Feb 2015 in reply to Johannes Link to this post

    I want to add that property Value is of type object so it can be string, int or else. That's why I have to use different DataTemplates/Controls to make Value editable via my UI. The code shown above is located inside my RadDataForms EditTemplate.
  3. UI for WPF is Visual Studio 2017 Ready
  4. Ivan Ivanov
    Admin
    Ivan Ivanov avatar
    1128 posts

    Posted 11 Feb 2015 Link to this post

    Hi,

    Please excuse me for the late reply. Generally, we rely on Validatior.ValidateObject to retrieve the validation errors of the current item. Here is the actual snippet of our source code:
    Validator.TryValidateObject(this.CurrentItem, new ValidationContext(this.CurrentItem, null, null), validationResults, true);
    Thus validation relies exclusively on the value of the properties, and not on editor bindings. Can you please confirm whether Value, Name and ID are members of one and the same type and Value is not a nested property to the type of DataForm's CurrentItem?

    Regards,
    Ivan Ivanov
    Telerik
     

    Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.

     
  5. Johannes
    Johannes avatar
    66 posts
    Member since:
    Dec 2012

    Posted 11 Feb 2015 in reply to Ivan Ivanov Link to this post

    Thanks for your reply. ID and Name are in the same ViewModel, for example ProductViewModel. ProductViewModel then would have this fields: ID (int), Name (string) and DataFields (ObservableCollection<DataFieldViewModel>). DataFieldViewModel then has properties Label, ToolTip and Value. So Value is not in the same ViewModel as ID and Name, it's in a nested ViewModel.

    As shown above I have an ItemsControl inside my RadDataForm that is bound to that ObservableCollection. I assumed that validation is automatically executed on every bound/visible value but you wrote that's not the case. So if I understand you correctly only RadDataForm's CurrentItem is validated. Is there some way to override/extend this? I have to validate the properties of my nested ViewModels, too.
  6. Johannes
    Johannes avatar
    66 posts
    Member since:
    Dec 2012

    Posted 11 Feb 2015 in reply to Johannes Link to this post

    Ok I've managed to extend validation for my needs. Please take a look at this:

    bool result = base.OnValidateItem(); // calls RadDataForm.ValidateItem
     
    if (DataForm != null)
    {
        var product = DataForm.CurrentItem as IProductDataItemViewModel;
     
        if (product != null)
        {
            var errors = new List<ValidationResult>();
     
            var productValidationResult = Validator.TryValidateObject(product, new ValidationContext(product, null, null), errors, true);
     
            if (productValidationResult == false)
            {
                result = false;
            }
     
            // Check DataFields in ProductViewModel
            foreach (var dataField in product.DataFields)
            {
                var dataFieldValidationResult = Validator.TryValidateObject(dataField, new ValidationContext(dataField, null, null), errors, true);
     
                if (dataFieldValidationResult == false)
                {
                    result = false;
                }
            }
     
            if (errors.Any())
            {
                // How to populate Errors to the UI?
            }
        }
    }
                 
    return result;



    When I check RadDataForm's ValidationSummary property I can see the errors for nested property Value but how can I populate them to the UI? There is a method



  7. Ivan Ivanov
    Admin
    Ivan Ivanov avatar
    1128 posts

    Posted 16 Feb 2015 Link to this post

    Hello,

    You can add your own validation errors to the UI like this:
    dataForm.ValidationSummary.Errors.Add(new Telerik.Windows.Controls.Data.ErrorInfo() { ErrorContent = "Name should be no shorter than 2 characters", SourceFieldDisplayName = "Name" });
    Please, be advised that these errors should be handled manually and they will not be automatically cleared as soon as he validation condition is met.

    Regards,
    Ivan Ivanov
    Telerik
     

    Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.

     
Back to Top
UI for WPF is Visual Studio 2017 Ready