2

我有一个实现 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,我的视图模型中没有任何属性;因此,我只能对 ObservableCollection 使用 IDataError,而不是集合中的单个项目,这对我没有帮助,因为我知道如何查看集合的“内部”。我也不能对我的 SelectedProjectExpenseItem 使用 IDataError。例如:

    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,它绑定到 ObservableCollection 中的 ItemNumber。

我正在寻找任何指导,因为这真的让我很困惑。

- - - - - - - - - - - - - - 编辑: - - - - - - - - - - --------

好的,我为我的 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”隐式转换为“System.Collections.Generic.IList”。存在显式转换(您是否缺少演员表?)

有任何想法吗?

- - - - - - - - - - - - - - 编辑: - - - - - - - - - - --------

我找到了这个链接,看看我是否可以复制这个人在做什么:

WPF-DataGrid 中的验证

4

4 回答 4

0

这些问题与在我的实现中使用 Dto 有关,或者至少与在其中没有实现 IDataErrorInfo 有关。我决定抛弃它们,直接使用实现 IDataErroInfo 和 wa-la 的业务对象,现在一切都运行良好。

于 2010-06-29T20:01:50.033 回答
0

不要使用ObservableCollectionof ,而是为Type (IE : )ProjectExpenseItemsDto创建一个 ViewModel并使其实现接口,然后在主 ViewModel 中使用 an 作为属性。ProjectExpenseItemsDtoProjectExpenseItemsDtoViewModelIDataErrorInfoObservableCollection<ProjectExpenseItemsDtoViewModel>

于 2010-06-24T22:54:08.407 回答
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属性。看到你的视图模型必须能够告诉视图有问题,所以 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>

谷歌wpf error templates阅读有关此示例的错误模板。以上将向有错误的文本框添加工具提示。

WPF 有几个活动部分,所以很容易迷路,但你会习惯的,只是需要时间 :)

希望这对您的旅程有所帮助。

于 2010-06-25T03:19:40.530 回答
0

好的,我发现了部分问题。IDataErrorInfo 没有触发的原因是因为我在 dg 的 SelectedItem 绑定上没有 ValidatesOnDataErrors=True:

            <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 中没有单独的属性有关。

哇,这个 wpf/mvvm 东西可以让一个人匆忙迷路。

于 2010-06-28T20:17:08.867 回答