Как заставить проверку показывать на UserControl - PullRequest
1 голос
/ 28 октября 2011

Я хочу, чтобы стандартная проверка красной границы со всплывающей подсказкой отображалась вокруг моего UserControl.Смотрите код ниже.У меня есть главная страница и UserControl.

UserControl имеет текстовое поле и кнопку.UserControls привязывается к свойству Id и отображает этот Id внутри TextBox.

На главной странице есть UserControl и TextBox.Они связаны с FirstValue и SecondValue.Оба свойства вызывают ошибку.Когда я набираю / меняю что-то в текстовом поле - я вижу границы и резюме.Когда я изменяю текст в своем UserControl - я вижу ошибку в сводке, но не вижу границы, а когда я нажимаю на ошибку - она ​​фокусирует кнопку, не переходит в TextBox.Как мне это исправить?Я хочу, чтобы весь UserControl находился внутри красной границы.

MainPage XAML:

<UserControl x:Class="SilverlightApplication1.MainPage"
    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"
    mc:Ignorable="d"
    d:DesignHeight="275" d:DesignWidth="402" xmlns:my="clr-namespace:SilverlightApplication1" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">

    <Grid x:Name="LayoutRoot" Background="White" Width="300" HorizontalAlignment="Left">
        <Grid.RowDefinitions>
            <RowDefinition Height="30" />
            <RowDefinition Height="40" />
            <RowDefinition Height="30" />
            <RowDefinition Height="30" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <TextBox Grid.Row="2" Margin="3" Text="{Binding SecondValue, Mode=TwoWay, NotifyOnValidationError=True}"/>
        <my:TestUserControl Margin="3" Id="{Binding FirstValue, Mode=TwoWay, NotifyOnValidationError=True}"/>
        <sdk:ValidationSummary Grid.Row="4" Name="validationSummary1" />
    </Grid>
</UserControl>

MainPage CS

using System.Windows.Controls;


namespace SilverlightApplication1
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;

    public partial class MainPage : UserControl, INotifyDataErrorInfo, INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
        readonly Dictionary<string, List<string>> _currentErrors;

        private string _firstValue;
        private string _secondValue;

        public MainPage()
        {
            InitializeComponent();
            _currentErrors = new Dictionary<string, List<string>>();
            _firstValue = "test1";
            _secondValue = "test2";
            LayoutRoot.DataContext = this;
        }


        public string FirstValue
        {
            get { return _firstValue; }

            set
            {
                _firstValue = value;
                CheckIfValueIsValid("FirstValue", value);
                this.OnPropertyChanged("FirstValue");
            }
        }

        public string SecondValue
        {
            get { return _secondValue; }
            set
            {
                _secondValue = value;
                CheckIfValueIsValid("SecondValue", value);
                this.OnPropertyChanged("SecondValue");
            }
        }

        public void CheckIfValueIsValid(string propertyName, string value)
        {
            ClearErrorFromProperty(propertyName);

            AddErrorForProperty(propertyName, "Bad value");
        }

        protected void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public IEnumerable GetErrors(string propertyName)
        {
            if (string.IsNullOrEmpty(propertyName))
            {
                return (_currentErrors.Values);
            }
            MakeOrCreatePropertyErrorList(propertyName);

            return _currentErrors[propertyName];
        }

        public bool HasErrors
        {
            get
            {
                return (_currentErrors.Where(c => c.Value.Count > 0).Count() > 0);
            }
        }

        void FireErrorsChanged(string property)
        {
            if (ErrorsChanged != null)
            {
                ErrorsChanged(this, new DataErrorsChangedEventArgs(property));
            }
        }

        public void ClearErrorFromProperty(string property)
        {
            MakeOrCreatePropertyErrorList(property);

            _currentErrors[property].Clear();
            FireErrorsChanged(property);
        }

        public void AddErrorForProperty(string property, string error)
        {
            MakeOrCreatePropertyErrorList(property);
            _currentErrors[property].Add(error);
            FireErrorsChanged(property);
        }

        void MakeOrCreatePropertyErrorList(string propertyName)
        {
            if (!_currentErrors.ContainsKey(propertyName))
            {
                _currentErrors[propertyName] = new List<string>();
            }
        }


    }
}

UserControl XAML:

<UserControl x:Class="SilverlightApplication1.TestUserControl"
    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"
    mc:Ignorable="d"
    d:DesignHeight="30" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>
        <Button Content="..." Grid.Column="1" Padding="10,0" />
        <TextBox Text="{Binding Id, Mode=TwoWay}" />
    </Grid>
</UserControl>

UserControl CS:

using System.Windows.Controls;

namespace SilverlightApplication1
{
    using System.ComponentModel;
    using System.Windows;

    public partial class TestUserControl : UserControl, INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public TestUserControl()
        {
            InitializeComponent();
            LayoutRoot.DataContext = this;
        }


        public string Id
        {
            get { return (string)base.GetValue(IdProperty); }
            set
            {
                base.SetValue(IdProperty, value);
                this.OnPropertyChanged("Id");
            }
        }

        public static DependencyProperty IdProperty =
            DependencyProperty.Register(
            "Id",
            typeof(string),
            typeof(TestUserControl),
            new PropertyMetadata(OnIdChanged));

        private static void OnIdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (DesignerProperties.IsInDesignTool) return;

            var lookup = d as TestUserControl;
            lookup.OnPropertyChanged("Id");
        }

        protected void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

    }
}

Ответы [ 2 ]

3 голосов
/ 30 октября 2011

Чтобы ваш пример работал, вы должны удалить весь код из файла TestUserControl.xaml.cs и исправить привязки. Как это:

<Button Content="..." Grid.Column="1" Padding="10,0" />
<TextBox Text="{Binding FirstValue, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnNotifyDataErrors=True}" />

И пустой код позади:

public partial class TestUserControl : UserControl
{
    public TestUserControl()
    {
        InitializeComponent();
    }
}

Далее ваш другой вопрос

отображать красную рамку вокруг всех 3 полей (один прямоугольник)

Это может быть достигнуто путем привязки к свойству HasError. По вашему коду это будет выглядеть так:

<Grid x:Name="LayoutRoot" Background="White">
   <!-- ... -->
   <Border BorderBrush="Red" BorderThickness="1" 
            Grid.ColumnSpan="2" IsHitTestVisible="False"
            Visibility="{Binding HasErrors, Converter={StaticResource BooleanToVisibilityConverter}}" />

Я добавил красный Border элемент, который становится видимым, когда для свойства HasError установлено значение true. Но вы должны вызвать OnPropertyChanged("HasError") где-то в вашем коде.

Другой способ: создать пользовательский элемент управления вместо UserControl. Я опубликовал чрезмерное описание того, как реализовать проверку в пользовательских элементах управления в качестве ответа на этот вопрос о проверке .

Я могу дать более конкретный ответ, но вы должны исправить код в своем посте, отделив модель представления от представления, потому что теперь трудно реализовать что-то на основе текущего кода. Проверьте мой пост о реализации проверки с использованием INotifyDataErrorInfo: WPF и проверка Silverlight .

Или вы можете загрузить мои классы проверки напрямую .

После этого код станет намного проще, и я смогу помочь вам с более сложными вопросами.

0 голосов
/ 30 октября 2011

Изменение

<TextBox Text="{Binding Id, Mode=TwoWay}" />

до

<TextBox Text="{Binding Id, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" />
...