INotifyDataErrorInfo не работает для WPF 4.5 DataGrids - PullRequest
4 голосов
/ 26 октября 2011

Я сделал простую реализацию INotifyDataErrorInfo в проекте WPF 4.5.Это новый интерфейс для WPF, но уже некоторое время он доступен в Silverlight.

Я знаю, что NET4.5 по-прежнему считается альфа-версией, но я пытаюсь понять, является ли это мой код или инфраструктура вошибка.

Интерфейс работает должным образом, но не работает, когда объект привязан к DataGrid.

Полученное исключение:

System.NullReferenceException не обработанопо коду пользователя
Сообщение = ссылка на объект не установлена ​​для экземпляра объекта.
Источник = PresentationFramework StackTrace: в MS.Internal.Data.ClrBindingWorker.OnDataErrorsChanged (INotifyDataErrorInfo indei, String propName) в MS.Internal.Data.PropertyPathWorker.OnErrorsChanged (Отправитель объекта, DataErrorsChangedEventArgs e) в System.Windows.WeakEventManager.ListenerList`1.DeliverEvent (Отправитель объекта, EventArgs e, тип managerType) в System.Windows.WeakEventEventMargs.ComponentModel.ErrorsChangedEventManager.OnErrorsChanged (Объектотправитель, DataErrorsChangedEventArgs арг) в INotifyDataErrorInfoTest.Person.NotifyErrorsChanged (строка собственности) в INotifyDataErrorInfoTest \ Person.cs: строка 109 в INotifyDataErrorInfoTest.Person.AddErrorForProperty (String свойство, String ошибка) в INotifyDataErrorInfoTest \ Person.cs: линия 122 на INotifyDataErrorInfoTest.Person.Validate (String propertyName) в INotifyDataErrorInfoTest \ Person.cs: строка 150 в INotifyDataErrorInfoTest.Person.set_FirstName (String value) в INotifyDataErrorInfoTest \ Person.cs: строка 18

код проекта ниже илиat http://dl.dropbox.com/u/14740106/INotifyDataErrorInfoTest.zip

Если все согласны с тем, что это ошибка, я опубликую ее в MS Connect.

Тестирование: к одному экземпляру объекта Person привязаны два текстовых поля.Установите для первого текстового поля значение Джеймса, и оно не пройдет проверку и отобразит красное поле.Если вы установите имя любого пользователя в сетке на Джеймса, будет сгенерировано исключение.

PS: я знаю, что это не MVVM, а просто чтобы доказать или опровергнуть проблему.

 public class Person : INotifyDataErrorInfo, INotifyPropertyChanged
    {
        string _firstName;
        public string FirstName
        {
            get { return _firstName; }
            set
            {
                _firstName = value;
                Validate("FirstName");
                OnPropertyChanged("FirstName");
            }
        }

        string _lastName;
        public string LastName
        {
            get { return _lastName; }
            set
            {
                _lastName = value;
                Validate("LastName");
                OnPropertyChanged("LastName");
            }
        }

        public Person()
        {
        }

        public Person(string first, string last)
        {
            this._firstName = first;
            this._lastName = last;
        }

        #region INotifyPropertyChanged Members

        /// <summary>
        /// Event to indicate that a property has changed.
        /// </summary>
        [field: NonSerialized]
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Called when a property is changed
        /// </summary>
        /// <param name="propertyName">The name of the property that has changed.</param>
        protected virtual void OnPropertyChanged(string propertyName)
        {
            OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
        }

        /// <summary>
        /// Called when a property is changed
        /// </summary>
        /// <param name="e">PropertyChangedEventArgs</param>
        protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
        {

            //Validate the property
            Validate(e.PropertyName);

            if (null != PropertyChanged)
            {
                PropertyChanged(this, e);
            }

        }

        #endregion

        #region INotifyDataErrorInfo Members

        public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
        private Dictionary<string, List<string>> _errors = new Dictionary<string, List<string>>();

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

            MakeOrCreatePropertyErrorList(propertyName);
            return _errors[propertyName];
        }

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

        void NotifyErrorsChanged(string property)
        {
            if (ErrorsChanged != null)
            {
                ErrorsChanged(this, new DataErrorsChangedEventArgs(property));
            }
        }
        public void ClearErrorFromProperty(string property)
        {
            MakeOrCreatePropertyErrorList(property);
            _errors[property].Clear();
            NotifyErrorsChanged(property);
        }
        public void AddErrorForProperty(string property, string error)
        {
            MakeOrCreatePropertyErrorList(property);
            _errors[property].Add(error);
            NotifyErrorsChanged(property);
        }

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

        #endregion

        /// <summary>
        /// Force the object to validate itself using the assigned business rules.
        /// </summary>
        /// <param name="propertyName">Name of the property to validate.</param>
        public void Validate(string propertyName)
        {
            if (string.IsNullOrEmpty(propertyName))
            {
                return;
            }

            if (propertyName == "FirstName")
            {
                if (FirstName == "James")
                {
                    AddErrorForProperty(propertyName, "FirstName can't be James");
                }
                else
                {
                    ClearErrorFromProperty(propertyName);
                }
            }
        }
    }

public class NameList : ObservableCollection<Person>
    {
        public NameList()
            : base()
        {
            Add(new Person("Willa", "Cather"));
            Add(new Person("Isak", "Dinesen"));
            Add(new Person("Victor", "Hugo"));
            Add(new Person("Jules", "Verne"));
        }
    }

   public partial class MainWindow : Window
    {

        Person _person = new Person();

        public MainWindow()
        {
            InitializeComponent();
            DataContext = this;
        }

        public Person Person
        {
            get { return _person; }
        }
}

<Window x:Class="INotifyDataErrorInfoTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:c="clr-namespace:INotifyDataErrorInfoTest"
        Title="MainWindow" Height="350" Width="525">

    <Window.Resources>
        <c:NameList x:Key="NameListData"/>
    </Window.Resources>
    <StackPanel>
        <StackPanel.Resources>
            <Style TargetType="TextBox">
                <Setter Property="Margin" Value="5"></Setter>
            </Style>
        </StackPanel.Resources>
        <TextBox Text="{Binding Person.FirstName, Mode=TwoWay, ValidatesOnNotifyDataErrors=True}"/>
        <TextBox Text="{Binding Person.LastName, Mode=TwoWay, ValidatesOnNotifyDataErrors=True}"/>
        <TextBlock>To generate an error, set the FirstName of any row to James.
        </TextBlock>
        <DataGrid ItemsSource="{Binding Source={StaticResource NameListData}}" AutoGenerateColumns="True"></DataGrid>
    </StackPanel>
</Window>

1 Ответ

6 голосов
/ 12 ноября 2011

Ответ ДА.Я открыл тикет в Microsoft , и они подтвердили, что код в порядке, и это ошибка в .NET 4.5 DataGrid.

Это наша ошибка, а не ваша.Когда вы редактируете ячейку DataGrid, DataGrid отбрасывает привязки для шаблона «display» и заменяет их привязками для шаблона «edit».Отброшенные привязки должны прекратить прослушивание события INDEI.ErrorsChanged.Они не (это ошибка), но они не готовы получить событие больше.Когда происходит событие, происходит сбой с нулевой ссылкой.

Это будет исправлено в финальной версии.Спасибо за то, что нашли и сообщили об этом.

Довольно большая ошибка, чтобы ждать до финальной версии.Будем надеяться, что это будет исправлено в следующем выпуске.

...