IDataErrorInfo на ObservableCollection - PullRequest
2 голосов
/ 25 июня 2010

У меня есть viewmodel, который реализует IDataError.В модели представления у меня есть ObservableCollection.ObservableCollection заполняет сетку данных в моем представлении:

    // the list that populates the datagrid
    public ObservableCollection<ProjectExpenseItemsDto> ListOfProjectExpenseItems
    {
        get { return listOfProjectExpenseItems; }
        set
        {
            if (listOfProjectExpenseItems != value)
            {
                listOfProjectExpenseItems = value;
                NotifyPropertyChanged("ListOfProjectExpenseItems");
            }
        }
    }

У меня также есть свойство, которое представляет выбранный элемент в сетке данных (оно основано на Dto):

    // the selected row in the datagrid
    public ProjectExpenseItemsDto SelectedProjectExpenseItem
    {
        get { return selectedProjectExpenseItem; }
        set
        {
            if (selectedProjectExpenseItem != value)
            {
                selectedProjectExpenseItem = value;
                NotifyPropertyChanged("SelectedProjectExpenseItem");
            }
        }
    }

Здесьтакое Dto:

namespace ProjectExpense.Model.Dto
{
    [DataContract]
    public class ProjectExpenseItemsDto
    {
        [DataMember]
        public int RowID { get; set; }
        [DataMember]
        public int ProjectExpenseID { get; set; }
        [DataMember]
        public string ItemNumber { get; set; }
        [DataMember]
        public string ItemDescription { get; set; }
        [DataMember]
        public decimal ItemUnitPrice { get; set; }
        [DataMember]
        public decimal ItemQty { get; set; }
        [DataMember]
        public string SupplierName { get; set; }
        [DataMember]
        public DateTime CreateDate { get; set; }
    }
}

Я хочу использовать IDataError для проверки значений в выбранной строке сетки данных (SelectedProjectExpenseItem), но, поскольку моя сетка привязана к ObservableCollection, у меня нет никаких свойств вмоя модель представления;поэтому я могу использовать только IDataError против ObservableCollection, а не отдельных элементов в коллекции, что мне не помогает, потому что я знаю способ увидеть «внутри» коллекции.Я также не могу использовать IDataError для моего SelectedProjectExpenseItem.Например:

    string IDataErrorInfo.this[string propertyName]
    {
        get
        {
            string result = string.Empty;
            propertyName = propertyName ?? string.Empty;
            if (propertyName == string.Empty || propertyName == "ItemNumber")
            {
                if (string.IsNullOrEmpty(SelectedProjectExpenseItem.ItemNumber))
                {
                    result = "Name cannot be blank!";
                }
            }
            return result;
        }
    }

это не срабатывает, потому что мой столбец таблицы данных не привязан к SelectedProjectExpenseItem.ItemNumber, он привязан к ItemNumber в ObservableCollection.

Я ищулюбое руководство, поскольку это действительно смущает меня.

---------------------------- РЕДАКТИРОВАТЬ: ---------------------------

Хорошо, я создал отдельную модель представления для моего DTO:

namespace ProjectExpense.ViewModels
{
    public class ProjectExpenseItemsDtoViewModel : ProjectExpenseItemsDto, IDataErrorInfo
    {
        public ProjectExpenseItemsDtoViewModel()
        {
            Initialize();
        }

        private void Initialize()
        {
        }

        #region Validation

        // string method
        static bool IsStringMissing(string value)
        {
            return String.IsNullOrEmpty(value) || value.Trim() == String.Empty;
        }

        #endregion

        #region IDataErrorInfo Members

        public string Error
        {
            get
            {
                return this[string.Empty];
            }
        }

        public string this[string propertyName]
        {
            get
            {
                string result = string.Empty;
                if (propertyName == "ItemNumber")
                {
                    if (IsStringMissing(this.ItemNumber))
                        result = "Item number cannot be empty!";
                    if (this.ItemNumber.Length > 50)
                        return "Item number exceeds 50 characters";
                }
                return result;
            }
        }

        #endregion
    }
}

Теперь у меня возникли проблемы со следующей строкой в ​​моем главном виртуальном компьютере:

IList<ProjectExpenseItemsDtoViewModel> iList = projectExpenseItemsRepository.GetProjectExpenseItems(ProjectExpenseID);
foreach (ProjectExpenseItemsDtoViewModel item in iList)
   ListOfProjectExpenseItems.Add(item);

Он говорит:

Невозможно неявно преобразовать тип 'System.Collections.Generic.IList'to' System.Collections.Generic.IList '.Существует явное преобразование (вам не хватает актеров?)

Есть идеи?

---------------------------- РЕДАКТИРОВАТЬ: ----------------------------

Я нашел этоссылка, посмотрим, смогу ли я скопировать то, что делает человек:

Validation-in-a-WPF-DataGrid

Ответы [ 4 ]

0 голосов
/ 30 июня 2010

Проблемы были связаны с использованием Dto в моей реализации или, по крайней мере, с отсутствием в них реализации IDataErrorInfo. Я решил снять их и использовать простые бизнес-объекты, которые реализуют IDataErroInfo и wa-la, теперь все работает прекрасно.

0 голосов
/ 25 июня 2010

Насколько я могу судить, проблема не в вашей модели представления, а в разметке в вашем представлении.Вы должны реализовать это в своем DTO, вы просто должны сказать своему взгляду, чтобы обратить внимание на IDataErrorInfo и что-то с этим сделать.

вы можете сделать следующее:

<dg:DataGrid ItemsSource="{StaticResource ListOfProjectExpenseItems}"/> >
<dg:DataGrid.Columns>
    <dg:DataGridTextColumn Header="ItemNumber" Binding="{Binding ItemNumber,ValidatesOnDataErrors=true}"/>
    <dg:DataGridTextColumn Header="ItemDescription" Binding="{Binding ItemDescription" />
</dg:DataGrid.Columns>
</dg:DataGrid>

Обратите внимание наValidatedOnDataErrors собственность.Посмотрите, что ваша view-модель должна быть в состоянии сказать представлению, что что-то не так, поэтому IDataErrorInfo - это интерфейс, который WPF по своей природе слушает, если его спрашивают.Если ваша привязка к свойству указывает wpf прослушивать его, то это произойдет.

И есть шаблоны ошибок по умолчанию, но если, скажем, вы хотите добавить всплывающую подсказку, чтобы сообщить пользователю о фактической ошибке, которая вам понадобитсясделайте что-то вроде этого

<Style x:Key="textBoxInError" TargetType="{x:Type TextBox}">
  <Style.Triggers>
    <Trigger Property="Validation.HasError" Value="true">
      <Setter Property="ToolTip"
        Value="{Binding RelativeSource={x:Static RelativeSource.Self},
                        Path=(Validation.Errors)[0].ErrorContent}"/>
    </Trigger>
  </Style.Triggers>
</Style>

Google wpf error templates, чтобы прочитать о шаблонах ошибок, таких как в этом примере. Вышеприведенное добавит всплывающую подсказку к текстовым полям с ошибкой

В WPF есть несколько движущихся частей, поэтому его легко потерять, но вы привыкнете к этому, это займет время:)

Надеюсь, это поможет вам в вашем путешествии.

0 голосов
/ 29 июня 2010

Хорошо, я нашел часть проблемы.Причина, по которой IDataErrorInfo не была запущена, была в том, что у меня не было ValidatesOnDataErrors = True для привязки SelectedItem для dg:

            <DataGrid ItemsSource="{Binding Path=ListOfProjectExpenseItems, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" AutoGenerateColumns="False" 
                Name="dgProjectExpenseItems" SelectionMode="Single" SelectionUnit="FullRow" CanUserResizeColumns="True" 
                RowStyle="{StaticResource RowStyle}" SelectedItem="{Binding Path=SelectedProjectExpenseItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" GridLinesVisibility="Horizontal" CanUserDeleteRows="True" CanUserAddRows="True">
            <DataGrid.RowValidationRules>
                <DataErrorValidationRule ValidationStep="UpdatedValue" />
                <ExceptionValidationRule ValidationStep="UpdatedValue" />
            </DataGrid.RowValidationRules>

            <DataGrid.Columns>
                <DataGridTextColumn Header="ID" Width="SizeToCells"  MinWidth="50" Binding="{Binding RowID}" />
                <DataGridTextColumn Header="Project Expense ID" Width="SizeToCells" Visibility="Hidden" MinWidth="0" Binding="{Binding ProjectExpenseID, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
                <DataGridTextColumn Header="Item Number" EditingElementStyle="{StaticResource CellEditStyle}" Width="SizeToCells" MinWidth="140" Binding="{Binding ItemNumber, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, ValidatesOnExceptions=True, NotifyOnValidationError=true }" />
                <DataGridTextColumn Header="Item Description" Width="SizeToCells" MinWidth="250" Binding="{Binding ItemDescription, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" />
                <DataGridTextColumn Header="Unit Price" Width="SizeToCells" MinWidth="90" Binding="{Binding ItemUnitPrice, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
                <DataGridTextColumn Header="Qty" Width="SizeToCells" MinWidth="65" Binding="{Binding ItemQty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
                <DataGridTextColumn Header="Supplier Name" Width="SizeToCells" MinWidth="200" Binding="{Binding SupplierName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
            </DataGrid.Columns>
        </DataGrid>

Мой IDataErroIno выглядит так:

    string IDataErrorInfo.this[string propertyName]
    {
        get
        {
            string result = string.Empty;
            propertyName = propertyName ?? string.Empty;
            if (propertyName == string.Empty || propertyName == "SelectedProjectExpenseItem")
            {
                if (SelectedProjectExpenseItem != null)
                {
                    if (IsStringMissing(SelectedProjectExpenseItem.ItemNumber))
                    {
                        result = "Item number cannot be blank!";
                        IsValid = false;
                    }
                }
            }
            return result;
        }
    }

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

вау, этот материал wpf / mvvm может быстро потерять парня.

0 голосов
/ 25 июня 2010

Вместо использования ObservableCollection из ProjectExpenseItemsDto создайте ViewModel для типа ProjectExpenseItemsDto (IE: ProjectExpenseItemsDtoViewModel) и заставьте его реализовать интерфейс IDataErrorInfo, затем используйте ObservableCollection<ProjectExpenseItemsDtoViewModel> в качестве свойствав основной ViewModel.

...