在我的应用程序中,我想验证用户在单元格上输入新项目时是否输入DataGrid中已存在的项目。我使用IDataErrorInfo
验证了我的业务对象。
我的目标如下:
class clsProducts : INotifyPropertyChanged, IDataErrorInfo
{
private string _ProductName;
private decimal _PurchaseRate;
private int _AvailableQty;
private int _Qty;
private decimal _Amount;
#region Property Getters and Setters
public string ProductName
{
get { return _ProductName; }
set
{
if (_ProductName != value)
{
_ProductName = value;
OnPropertyChanged("ProductName");
}
}
}
public decimal PurchaseRate
{
get { return _PurchaseRate; }
set
{
_PurchaseRate = value;
OnPropertyChanged("PurchaseRate");
}
}
public int AvailableQty
{
get { return _AvailableQty; }
set
{
_AvailableQty = value;
OnPropertyChanged("AvailableQty");
}
}
public int Qty
{
get { return _Qty; }
set
{
_Qty = value;
this._Amount = this._Qty * this._PurchaseRate;
OnPropertyChanged("Qty");
OnPropertyChanged("Amount");
}
}
public decimal Amount
{
get { return _Amount; }
set
{
_Amount = value;
OnPropertyChanged("Amount");
}
}
#endregion
#region IDataErrorInfo Members
public string Error
{
get
{
StringBuilder error = new StringBuilder();
// iterate over all of the properties
// of this object - aggregating any validation errors
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(this);
foreach (PropertyDescriptor prop in props)
{
string propertyError = this[prop.Name];
if (!string.IsNullOrEmpty(propertyError))
{
error.Append((error.Length != 0 ? ", " : "") + propertyError);
}
}
return error.ToString();
}
}
public string this[string name]
{
get
{
string result = null;
if (name == "ProductName")
{
if (this._ProductName != null)
{
int count = Global.ItemExist(this._ProductName);
if (count == 0)
{
result = "Invalid Product "+this._ProductName;
}
}
}
else if (name == "Qty")
{
if (this._Qty > this._AvailableQty)
{
result = "Qty must be less than Available Qty . Avaialble Qty : " + this._AvailableQty;
}
}
return result;
}
}
#endregion
#region INotifyPropertyChanged Members
// Declare the event
public event PropertyChangedEventHandler PropertyChanged;
//// Create the OnPropertyChanged method to raise the event
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
#endregion
}
我的xaml是:
<my:DataGrid Name="dgReceiveInventory" RowStyle="{StaticResource RowStyle}" ItemsSource="{Binding}" GotFocus="dgReceiveInventory_GotFocus" CanUserDeleteRows="False" CanUserReorderColumns="False" CanUserResizeColumns="False" CanUserResizeRows="False" CanUserSortColumns="False" RowHeight="23" SelectionUnit="Cell" AutoGenerateColumns="False" Margin="12,84,10,52" BeginningEdit="dgReceiveInventory_BeginningEdit">
<my:DataGrid.Columns>
<!--0-Product Column-->
<my:DataGridTemplateColumn Header="Product Name" Width="200">
<my:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Style="{StaticResource TextBlockInError}" Text="{Binding ProductName,ValidatesOnDataErrors=True}" ></TextBlock>
</DataTemplate>
</my:DataGridTemplateColumn.CellTemplate>
<my:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox x:Name="txtbxProduct" Style="{StaticResource TextBoxInError}" Text="{Binding Path=ProductName,UpdateSourceTrigger=LostFocus,ValidatesOnDataErrors=True}" TextChanged="txtbxProduct_TextChanged" PreviewKeyDown="txtbxProduct_PreviewKeyDown" >
</TextBox>
</DataTemplate>
</my:DataGridTemplateColumn.CellEditingTemplate>
</my:DataGridTemplateColumn>
<!--1-Purchase Rate Column-->
<my:DataGridTextColumn Header="Purchase Rate" Width="100" Binding="{Binding PurchaseRate}" IsReadOnly="True"></my:DataGridTextColumn>
<!--2-Avaialable Qty Column-->
<my:DataGridTextColumn Header="AvailableQty" Binding="{Binding AvailableQty}" IsReadOnly="True" Visibility="Hidden"></my:DataGridTextColumn>
<!--3-Qty Column-->
<my:DataGridTextColumn Header="Qty" Binding="{Binding Qty,ValidatesOnExceptions=True,ValidatesOnDataErrors=True}" EditingElementStyle="{StaticResource TextBoxInError}">
</my:DataGridTextColumn>
<!--4-Amount Column-->
<my:DataGridTextColumn Header="Amount" Width="100" Binding="{Binding Amount}" ></my:DataGridTextColumn>
</my:DataGrid.Columns>
</my:DataGrid>
现在我想向用户展示,如果他在datagrid单元格中创建了重复条目,该怎么做?
答案 0 :(得分:1)
您无法使用IDataErrorInfo
界面在模型或数据类型类中执行此功能,因为您无法访问其他对象。相反,您必须在视图模型中执行此操作。但是,您可以使用该界面报告错误。我通过在我的数据类型基类中添加一个属性来扩展其功能:
public virtual ObservableCollection<string> ExternalErrors
{
get { return externalErrors; }
}
正如您所看到的,我的处理有多处错误,但您可以轻松将其更改为:
public virtual string ExternalError
{
get { return externalError; }
}
然后我'将'插入我的Errors
财产:
public override ObservableCollection<string> Errors
{
get
{
errors = new ObservableCollection<string>();
errors.AddUniqueIfNotEmpty(this["Name"]);
errors.AddUniqueIfNotEmpty(this["EmailAddresses"]);
errors.AddUniqueIfNotEmpty(this["StatementPrefixes"]);
errors.AddRange(ExternalErrors);
return errors;
}
}
同样,我已经调整了此界面以返回多个错误,但您可以将其更改为:
public override string Error
{
get
{
error = string.Empty;
if ((error = this["Name"])) != string.Empty) return error;
if ((error = this["EmailAddresses"])) != string.Empty) return error;
if ((error = this["Name"])) != string.Empty) return error;
if (ExternalError != string.Empty) return ExternalError;
return error;
}
}
顺便说一下,只调用实际验证的索引器而不是使用反射调用所有属性的示例,远更有效。但是,这是你的选择。
现在我们有了这个ExternalError
属性,我们可以使用它来显示视图模型中的外部错误消息(创建一个包含要绑定到DataGrid.ItemsSource
属性的collection属性的类)。
如果您使用ICommand
个对象,则可以将此代码放入Save命令的CanExecute
方法中:
public bool CanSave(object parameter)
{
clsProducts instance = (clsProducts)parameter;
instance.ExternalError = YourCollectionProperty.Contains(instance) ?
"The values must be unique" : string.Error;
// Perform your can save checks here
}
请注意,您需要在数据类型对象中实施Equals
方法才能实现此目的。有很多类似的方法来实现这一点,我相信从这个例子中你可以找到一个适合你的方法。