C# 正在验证项目WPF中单击按钮时的控件
我有一个ItemsControl,它带有一个包含两个组合框的item模板。对于任何给定项,如果第一个组合框具有选定值,则需要第二个组合框。我已经在视图模型上使用IDataErrorInfo设置了此验证 我希望在用户尝试保存时执行验证,而不是在用户选择ComboBox 1中的值时将ComboBox#2标记为无效。在一个你甚至还没有机会进入的领域里,对你做了错事,以一种形式“大喊大叫”是有点烦人的 通常,您可以通过检索ComboBox的BindingExpression并调用UpdateSource()来强制执行此验证,然后通过调用validation.GetHasError()传递ComboBox来确定是否存在错误。由于组合框是由ItemsControl动态生成的,因此访问它并不容易。所以我有两个问题:1。单击“保存”按钮时,如何确保已对所有控件执行验证。2.单击“保存”按钮时,如何检查是否存在验证错误。即使其中的ComboBox2有错误,ItemsControl的Validation.GetHasError仍然为false。谢谢 编辑: 我随后实现了IDataErrorInfo,以验证combobox属性之间的相关性C# 正在验证项目WPF中单击按钮时的控件,c#,wpf,validation,data-binding,itemscontrol,C#,Wpf,Validation,Data Binding,Itemscontrol,我有一个ItemsControl,它带有一个包含两个组合框的item模板。对于任何给定项,如果第一个组合框具有选定值,则需要第二个组合框。我已经在视图模型上使用IDataErrorInfo设置了此验证 我希望在用户尝试保存时执行验证,而不是在用户选择ComboBox 1中的值时将ComboBox#2标记为无效。在一个你甚至还没有机会进入的领域里,对你做了错事,以一种形式“大喊大叫”是有点烦人的 通常,您可以通过检索ComboBox的BindingExpression并调用UpdateSource
public class IntroViewModel : INotifyPropertyChanged, IDataErrorInfo
{
public Guid ClassScheduleID
{
get { return _intro.ClassScheduleID; }
set
{
_intro.ClassScheduleID = value;
OnPropertyChanged("ClassScheduleID");
//OnPropertyChanged("TrialDate"); //This will trigger validation on ComboBox2 when bound ComboBox1 changes
}
}
public DateTime TrialDate
{
get { return _intro.TrialDate; }
set
{
_intro.TrialDate = value;
OnPropertyChanged("TrialDate");
}
}
public string Error
{
get { return null; }
}
public string this[string columnName]
{
get { return ValidateProperty(columnName); }
}
private string ValidateProperty(string propertyName)
{
string error = null;
switch (propertyName)
{
case "TrialDate":
if (_intro.TrialDate == DateTime.MinValue && _intro.ClassScheduleID != Guid.Empty)
error = "Required";
break;
default:
error = null;
break;
}
return error;
}
}
我试图根据一些假设创建您需要的行为 样品 XAML
主虚拟机
公共视图模型()
{
AddItem=newsimpleCommand(i=>Data.Add(newdataviewmodel(newdatamodel())));
保存=新的SimpleCommand(i=>
{
foreach(数据中的var vm)
{
vm.ValidateAndSave();
}
}
);
数据=新的ObservableCollection();
}
公共可观测收集数据{get;set;}
公共ICommand附加项{get;set;}
公共ICommand保存{get;set;}
数据虚拟机与模型
公共类数据模型
{
公共对象值1{get;set;}
公共对象值2{get;set;}
}
公共类DataViewModel:INotifyPropertyChanged
{
数据模型;
公共数据视图模型(数据模型)
{
this.model=模型;
IsValid=true;
}
对象_值1;
公共物品价值1
{
得到
{
返回_值1;
}
设置
{
_value1=值;
}
}
对象_值2;
公共物品价值2
{
得到
{
返回_值2;
}
设置
{
_value2=值;
}
}
公共bool有效{get;set;}
public void ValidateAndSave()
{
IsValid=!(\u value1!=null&&u value2==null);
PropertyChanged(此,新PropertyChangedEventArgs(“IsValid”);
如果(有效)
{
model.Value1=_Value1;
model.Value2=_Value2;
}
}
公共事件属性更改事件处理程序属性更改;
}
因此,当您单击“保存”时,VM将验证所有项目,并仅保存那些有效的项目。否则会将IsValid属性标记为false,这将通知UI我无法告诉您如何在代码中实现
IDataErrorInfo
接口,但在我的实现中,做您想做的事情很简单。对于未来的用户,您可以在MSDN的页面上找到有关此接口的信息。在链接页面上,您将看到需要实现项
索引器和错误
属性
这就是您所需要的,因为如果您正确地实现了它,那么您只需检查error
属性的值,就可以发现您的数据(实现)项是否有错误:
bool hasError = string.IsNullOrEmpty(yourDataTypeInstance.Error);
if (!hasError) Save(yourDataTypeInstance);
else MessageBox.Show("Invalid data!");
更新>>> 请尝试使用此选项:
public DateTime TrialDate
{
get { return _intro.TrialDate; }
set
{
_intro.TrialDate = value;
OnPropertyChanged("TrialDate");
OnPropertyChanged("Error");
}
}
public string Error
{
get { return this["TrialDate"]; }
}
剩下的我就交给你们去做,基本上就是管理
string
s.下面是我在等待答案时如何完成的。初始化保存时,将调用ValidateTrials()以确保已对组合框触发验证,然后调用TrialsHaveErrors()以检查组合框上是否存在验证错误。这是我想要避免的暴力方法,但它确实有效
//Force validation on each combobox2
private void ValidateTrials()
{
foreach (IntroViewModel introVm in icTrials.Items)
{
ContentPresenter cp = (ContentPresenter)icTrials.ItemContainerGenerator.ContainerFromItem(introVm);
if (cp == null) continue;
ComboBox cb2 = (ComboBox)cp.ContentTemplate.FindName("cb2", (FrameworkElement)cp);
//Update the source to force validation.
cb2.GetBindingExpression(ComboBox.SelectedValueProperty).UpdateSource();
}
}
//Recursively searches the Visual Tree for ComboBox elements and checks their errors state
public bool TrialsHaveError(DependencyObject ipElement)
{
if (ipElement!= null)
{
for (int x = 0; x < VisualTreeHelper.GetChildrenCount(ipElement); x++)
{
DependencyObject child = VisualTreeHelper.GetChild(ipElement, x);
if (child != null && child is ComboBox)
{
if (Validation.GetHasError(child))
return true;
}
if (TrialsHaveError(child)) return true; //We found a combobox with an error
}
}
return false;
}
//强制对每个combobox2进行验证
私有void ValidateTrials()
{
foreach(icTrials.Items中的IntroViewModel introVm)
{
ContentPresenter cp=(ContentPresenter)icTrials.ItemContainerGenerator.ContainerFromItem(introVm);
如果(cp==null)继续;
ComboBox cb2=(ComboBox)cp.ContentTemplate.FindName(“cb2”,(FrameworkElement)cp);
//更新源以强制验证。
cb2.GetBindingExpression(ComboBox.SelectedValueProperty).UpdateSource();
}
}
//递归地在可视树中搜索ComboBox元素并检查其错误状态
公共布尔TrialsHaveError(DependencyObject ipElement)
{
if(ipElement!=null)
{
for(int x=0;x
<ItemsControl Name="icTrials" ItemsSource="{Binding Intros}" Margin="10,6,10,0" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid Grid.Row="2">
<ComboBox Name="cb1"
SelectedValuePath="ID"
SelectedValue="{Binding Path=ClassScheduleID, Converter={StaticResource nullEmptyConverter}, ConverterParameter=System.Guid}"
ItemsSource="{Binding ClassesSource}">
<ComboBox.ItemTemplate>
<DataTemplate>
...
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<ComboBox Name="cb2"
ItemsSource="{Binding AvailableStartDates}"
DisplayMemberPath="Date"
ItemStringFormat="{}{0:d}"
SelectedValue="{Binding Path=TrialDate, Converter={StaticResource nullEmptyConverter}, ConverterParameter=System.DateTime, ValidatesOnDataErrors=True}">
</ComboBox>
</Grid>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>