Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/rust/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 正在验证项目WPF中单击按钮时的控件_C#_Wpf_Validation_Data Binding_Itemscontrol - Fatal编程技术网

C# 正在验证项目WPF中单击按钮时的控件

C# 正在验证项目WPF中单击按钮时的控件,c#,wpf,validation,data-binding,itemscontrol,C#,Wpf,Validation,Data Binding,Itemscontrol,我有一个ItemsControl,它带有一个包含两个组合框的item模板。对于任何给定项,如果第一个组合框具有选定值,则需要第二个组合框。我已经在视图模型上使用IDataErrorInfo设置了此验证 我希望在用户尝试保存时执行验证,而不是在用户选择ComboBox 1中的值时将ComboBox#2标记为无效。在一个你甚至还没有机会进入的领域里,对你做了错事,以一种形式“大喊大叫”是有点烦人的 通常,您可以通过检索ComboBox的BindingExpression并调用UpdateSource

我有一个ItemsControl,它带有一个包含两个组合框的item模板。对于任何给定项,如果第一个组合框具有选定值,则需要第二个组合框。我已经在视图模型上使用IDataErrorInfo设置了此验证

我希望在用户尝试保存时执行验证,而不是在用户选择ComboBox 1中的值时将ComboBox#2标记为无效。在一个你甚至还没有机会进入的领域里,对你做了错事,以一种形式“大喊大叫”是有点烦人的

通常,您可以通过检索ComboBox的BindingExpression并调用UpdateSource()来强制执行此验证,然后通过调用validation.GetHasError()传递ComboBox来确定是否存在错误。由于组合框是由ItemsControl动态生成的,因此访问它并不容易。所以我有两个问题:1。单击“保存”按钮时,如何确保已对所有控件执行验证。2.单击“保存”按钮时,如何检查是否存在验证错误。即使其中的ComboBox2有错误,ItemsControl的Validation.GetHasError仍然为false。谢谢

编辑: 我随后实现了IDataErrorInfo,以验证combobox属性之间的相关性

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>