Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Apply Validation Rule to ListView's ItemsSource property

I'd like to validate a ListView by checking if the ItemsSource contains an empty collection. Here's the XAML.

<ListView x:Name="lstvItemsInGroup" 
            <ListView.ItemsSource>
                <Binding Path="ItemsInGroup" Mode="OneWay" UpdateSourceTrigger="PropertyChanged">
                    <Binding.ValidationRules>
                        <local:CollectionNotEmptyValidationRule ErrorMessage="You must select at least one item" />
                    </Binding.ValidationRules>
                </Binding> 
            </ListView.ItemsSource>

        </ListView>

Here's the ValidationRule.

public class CollectionNotEmptyValidationRule : ValidationRule
    {
        public string ErrorMessage
        { get; set; }



    public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
    {
        ValidationResult lResult = null;

        IEnumerable<object> lCollection = (IEnumerable<object>)value;
        if (lCollection == null || lCollection.Count() == 0)
        {
            lResult = new ValidationResult(false, ErrorMessage);
        }
        else
        {
            lResult = new ValidationResult(true, null);
        }

        return lResult;
    }

I am forcing the validation upon loading the usercontrol with

lstvItemsInGroup.GetBindingExpression(ListView.ItemsSourceProperty).UpdateSource();

But the ValidationRule isn't even called, I have a breakpoint in the first line and nothing.

Any clues?

Thank you.

like image 455
So Many Goblins Avatar asked Jan 21 '23 17:01

So Many Goblins


2 Answers

Here http://msdn.microsoft.com/en-us/library/system.windows.data.bindingexpression.updatesource.aspx it is said that the UpdateSource method only updates the source if the binding is in TwoWay or OneWayToSource modes. So, try setting Mode=TwoWay on your binding.

like image 192
Pavlo Glazkov Avatar answered Jan 29 '23 01:01

Pavlo Glazkov


This works:

public class CollectionNotEmptyValidationRule : ValidationRule
{
    public CollectionNotEmptyValidationRule()
        : base(ValidationStep.RawProposedValue, true)
    {
    }

    public string ErrorMessage { get; set; }

    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        return (value as IEnumerable<object>)?.Any() == true
            ? ValidationResult.ValidResult
            : new ValidationResult(false, ErrorMessage);
    }
}

<ListView>
    <ListView.ItemsSource>
        <Binding Mode="OneWay"
                    Path="Empty"
                    UpdateSourceTrigger="PropertyChanged">
            <Binding.ValidationRules>
                <local:CollectionNotEmptyValidationRule ErrorMessage="Collection cannot be empty" />
            </Binding.ValidationRules>
        </Binding>
    </ListView.ItemsSource>
</ListView>

Doing it like this does not track collection changes.

If you want that you can use:

public class MinValidationRule : ValidationRule
{
    public static readonly DependencyProperty AssertMinProperty = DependencyProperty.RegisterAttached(
        "AssertMin",
        typeof(int),
        typeof(MinValidationRule),
        new PropertyMetadata(default(int)));

    public MinValidationRule()
        : base(ValidationStep.ConvertedProposedValue, true)
    {
    }

    public string ErrorMessage { get; set; }

    public int Min { get; set; }

    public static void SetAssertMin(DependencyObject element, int value)
    {
        element.SetValue(AssertMinProperty, value);
    }

    public static int GetAssertMin(DependencyObject element)
    {
        return (int)element.GetValue(AssertMinProperty);
    }

    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        return ((int)value) >= Min
            ? ValidationResult.ValidResult
            : new ValidationResult(false, ErrorMessage);
    }
}

<ListView MinHeight="20" ItemsSource="{Binding VmItems}">
    <local:MinValidationRule.AssertMin>
        <Binding Path="Items.Count" RelativeSource="{RelativeSource Self}">
            <Binding.ValidationRules>
                <local:MinValidationRule ErrorMessage="Collection must have at least one item" Min="1" />
            </Binding.ValidationRules>
        </Binding>
    </local:MinValidationRule.AssertMin>
</ListView>
like image 34
Johan Larsson Avatar answered Jan 29 '23 02:01

Johan Larsson