2010-06-24 2 views
2

У меня есть viewmodel, который реализует IDataError. В viewmodel у меня есть ObservableCollection. ObservableCollection заполняет DataGrid, на мой взгляд:IDataErrorInfo on 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 для проверки значений в выбранной строке DataGrid (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; 
     } 
    } 

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

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

---------------------------- EDIT: --------------- -------------

Хорошо, я создал отдельный ViewModel для моего 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 
    } 
} 

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

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

Он говорит:

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

Любые идеи?

---------------------------- EDIT: --------------- -------------

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

Validation-in-a-WPF-DataGrid

ответ

0

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

0

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

+0

Вы хотите создать отдельный vm для dto и использовать это vm в главном? Будет ли dto vm реализовывать какие-либо свойства, такие как имена полей из Dto? Хммм, позвольте мне взглянуть на это. Я вернусь после того, как попробую. Благодарю. – steveareeno

+0

Ненавижу быть беспокойством, но не могли бы вы привести мне пример того, как этот vm может выглядеть? – steveareeno

+0

Возможно, вам нужно взглянуть на этот пример: http://www.codeproject.com/KB/WPF/WPFDataGridExamples.aspx#errorinfo, его та же идея. –

0

Насколько я могу судить, проблема не в вашей модели просмотра, а в разметке на вашем экране. Вы должны реализовать его на своем 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 собственность. Посмотрите, что ваш viewmodel должен иметь возможность сказать, что что-то не так, поэтому 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 читать о шаблонах ошибок например this example. Вышеприведенное добавит всплывающую подсказку в текстовые поля с ошибкой.

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

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

+0

У меня ранее были ValidatesOnDataErrors в xaml, и у меня тоже были стили. На самом деле поле my ItemQty (десятичное) работает, если я набираю символ или его пустоту, и это не имеет ни стилей, ни чего-либо, применяемого к dg. Вы абсолютно правы в wpf и mvvm. Трудно даже задать вопрос из-за количества степеней разделения между вашей базой данных и представлением. В моем случае у меня есть SQL Server DB, EF, Repository, Dto, ViewModel, View. – steveareeno

+0

BTW, спасибо за ответ! – steveareeno

0

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

  <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; 
     } 
    } 

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

wow, этот материал wpf/mvvm может заставить парня потеряться в спешке.

 Смежные вопросы

  • Нет связанных вопросов^_^