none
Не могу разобраться с ValidationRule в WPF RRS feed

  • Вопрос

  • Здравствуйте. Подскажите пожалуйста как сделать валидацию которая бы работала так: 
    На форме есть комбобоксы которые генерируются программно. Нажимаем на кнопку и на форму добавляется новый комбобкс. Я сделал их своем юзер контроле и туда же поместил разметку с валидацией. Есть список элементов которые можно выбрать , но нельзя чтобы в двух комбобоксах был выбран один и тот же элемент.

    Я сделал вот так 
    Код C#
    1
    2
    3
    4
    5
    6
    7
    
    <ComboBox.SelectedItem>
                <Binding Path="SelectemModel" UpdateSourceTrigger="PropertyChanged">
                    <Binding.ValidationRules>
                        <c:SelectedItemRule Что тут написать???></c:SelectedItemRule>
                    </Binding.ValidationRules>
                </Binding>
            </ComboBox.SelectedItem>
    И в самом классе с валидацией пишу так 
    Код C#
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    
    public class SelectedItemRule : ValidationRule
        {
            private List<string> _currentItemList;
     
            public List<string> CurrentListItem
            {
                get { return _currentItemList; }
                set { _currentItemList = value; }
            }
     
            public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
            {
                try
                {
                    if ((string)value != null)
                    {
                        CurrentListItem.Add((string)value);
                    }
                }
                catch (Exception)
                {
                    return new ValidationResult(false, "Данное значение уже было выбрано");
                }
                return new ValidationResult(true, null);
            }
        }
    Но мне то еще нужно как то коллецию прицепить CurrentListItem
    в которую будут попадать элементы выбранные ранее 


Ответы

  • Добрый день.

    Задача очень напоминает "специально усложненную". У вас есть UserControl на котором генерируются ComboBox-ы? Ну и замечательно, проверяйте допустимость значений не у отдельного ComboBox, а в рамках всего вашего UserControlа.

    Вот, небольшой пример.

    Я добавил у проект UserControl c вот таким XAML:

    <UserControl x:Class="WpfApplication10.UserControl1"
                 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" 
                 mc:Ignorable="d" 
                 d:DesignHeight="300" d:DesignWidth="300">
        <StackPanel x:Name="spMain">
            <Button Content="Add" Click="Button_Click" />
        </StackPanel>
    </UserControl>

    Вот код:

    public partial class UserControl1 : UserControl
    {
        public UserControl1()
        {
            InitializeComponent();
        }
    
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            int[] data = { 1, 2, 3, 4, 5 };
            ComboBox cb = new ComboBox();
            cb.ItemsSource = data;
            MyValidationRule rule = new MyValidationRule(GetValidationError);
            Binding bnd = new Binding();
            bnd.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
            bnd.ValidationRules.Add(rule);
            bnd.Path = new PropertyPath("A");
            bnd.Source = new TempClass() { A = 10 };
            cb.SetBinding(ComboBox.SelectedItemProperty, bnd);
            spMain.Children.Add(cb);
        }
    
        private string GetValidationError(int? p_value)
        {
            string result = null;
            if (p_value.HasValue)
            {
                int count = spMain.Children.OfType<ComboBox>().Cast<ComboBox>().Count(cb => (cb.SelectedItem as int?) == p_value.Value);
                if (count >= 1)
                {
                    result = "Это значение уже используется";
                }
            }
            return result;
        }
    }

    Правило у меня имеет вот такой вид:

    class MyValidationRule : ValidationRule
    {
        private Func<int?, string> _getValidationError;
    
        public MyValidationRule(Func<int?, string> p_getValidationError)
        {
            _getValidationError = p_getValidationError;
        }
    
        public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
        {
            ValidationResult result = new ValidationResult(true, null);
            if (_getValidationError != null && value is int?)
            {
                string error = _getValidationError((int?)value);
                if (!string.IsNullOrWhiteSpace(error))
                {
                    result = new ValidationResult(false, error);
                }
            }
            return result;
        }
    }

    Ну и вот так это все работает:

    Отвечающий

Все ответы

  • Я же кажется объяснял вам как ValidationRule работает и зачем он нужен.

    В частности в данной задаче одним ValidationRule не обойтись. Как узнать в каких комбобксах какие позиции выбраны?

    Да и других подводных камней вполне хватает. Например вы выбрали позицию 1 в ComboBox1, а потом выбрали ее же в ComboBox2.ValidationRule сработал и выбор в ComboBox2 проигнорировался, но потом в ComboBox1 я выбрал позицию 2. По идее ComboBox2 теперь может выбирать позицию 1, но дойдет ли это до пользователя?

    В общем ответов в топике не было так долго именно и за хитромудрости вашей задачи.

    Пока откровенно говоря идей нет. Может мои мысли натолкнут вас на идеи, которые в свою очередь натолкнут на идеи меня )


    VB.Net - WPF, WinRT, WP

    8 июня 2014 г. 15:43
    Отвечающий
  • Добрый день.

    Задача очень напоминает "специально усложненную". У вас есть UserControl на котором генерируются ComboBox-ы? Ну и замечательно, проверяйте допустимость значений не у отдельного ComboBox, а в рамках всего вашего UserControlа.

    Вот, небольшой пример.

    Я добавил у проект UserControl c вот таким XAML:

    <UserControl x:Class="WpfApplication10.UserControl1"
                 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" 
                 mc:Ignorable="d" 
                 d:DesignHeight="300" d:DesignWidth="300">
        <StackPanel x:Name="spMain">
            <Button Content="Add" Click="Button_Click" />
        </StackPanel>
    </UserControl>

    Вот код:

    public partial class UserControl1 : UserControl
    {
        public UserControl1()
        {
            InitializeComponent();
        }
    
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            int[] data = { 1, 2, 3, 4, 5 };
            ComboBox cb = new ComboBox();
            cb.ItemsSource = data;
            MyValidationRule rule = new MyValidationRule(GetValidationError);
            Binding bnd = new Binding();
            bnd.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
            bnd.ValidationRules.Add(rule);
            bnd.Path = new PropertyPath("A");
            bnd.Source = new TempClass() { A = 10 };
            cb.SetBinding(ComboBox.SelectedItemProperty, bnd);
            spMain.Children.Add(cb);
        }
    
        private string GetValidationError(int? p_value)
        {
            string result = null;
            if (p_value.HasValue)
            {
                int count = spMain.Children.OfType<ComboBox>().Cast<ComboBox>().Count(cb => (cb.SelectedItem as int?) == p_value.Value);
                if (count >= 1)
                {
                    result = "Это значение уже используется";
                }
            }
            return result;
        }
    }

    Правило у меня имеет вот такой вид:

    class MyValidationRule : ValidationRule
    {
        private Func<int?, string> _getValidationError;
    
        public MyValidationRule(Func<int?, string> p_getValidationError)
        {
            _getValidationError = p_getValidationError;
        }
    
        public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
        {
            ValidationResult result = new ValidationResult(true, null);
            if (_getValidationError != null && value is int?)
            {
                string error = _getValidationError((int?)value);
                if (!string.IsNullOrWhiteSpace(error))
                {
                    result = new ValidationResult(false, error);
                }
            }
            return result;
        }
    }

    Ну и вот так это все работает:

    Отвечающий