如何在 ItemsControl 内的 TextBox 上使用 ValidatesOnDataErrors

发布于 2024-11-15 17:52:40 字数 4414 浏览 10 评论 0原文

我正在尝试使用 IDataErrorInfo 验证 TextBox 的内容。下面列表的来源是一个List,并且显示每一项。当我将 ValidatesOnDataErrors=True 放入文本框上文本的绑定中时,它无法按预期工作。我该怎么做?

<ItemsControl ItemsSource="{Binding Trainings}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <StackPanel>
                    <TextBlock Text="{Binding MobileOperator}" />
                    <TextBlock Text="{Binding LastUpdate}"/>
                </StackPanel>
                <StackPanel>
                    <TextBlock Text="Number trained*" />                        
                    <!-- ValidatesOnDataErrors doesn't work here-->
                    <TextBox 
                        Text="{Binding NumberTrained, 
                                       ValidatesOnDataErrors=True}"/>
                </StackPanel>
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

的精简版本

更新:发布 Model、ViewModel、View 和 CodeBehind ViewModel 以及 Model

public class MyViewModel : IDataErrorInfo, INotifyPropertyChanged
{
    public MyViewModel() 
    {
        Trainings = new List<MyModel>
        {
            new MyModel { NumberTrained = 5, MobileOperator = "MO 1", LastUpdate =         DateTime.Now },
            new MyModel { NumberTrained = 1, MobileOperator = "MO 2", LastUpdate = DateTime.Now },
        };

        OkButtonCommand = new ButtonCommand(OnClick);
    }

    private void OnClick()
    {
        PropertyChanged(this, new PropertyChangedEventArgs(""));
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public ICommand OkButtonCommand { get; private set; }
    public List<MyModel> Trainings { get; private set; }
    public string Error { get { return null; } }

    public string this[string columnName]
    {
        get
        {
            string error = null;
            switch (columnName)
            {
                case "NumberTrained":
                    error = "error from IDataErrorInfo";
                    break;
            }
            return error;
        }
    }
}

public class MyModel
{
    public string MobileOperator { get; set; }
    public DateTime LastUpdate { get; set; }
    public int NumberTrained { get; set; }
}

public class ButtonCommand : ICommand
{
    private Action _handler;
    public event EventHandler CanExecuteChanged;

    public ButtonCommand(Action handler) { _handler = handler; }
    public bool CanExecute(object parameter) { return true; }
    public void Execute(object parameter) { _handler(); }
}

Code Behind

public partial class MainPage : UserControl
{
    public MainPage()
    {
        InitializeComponent();

        DataContext = new MyViewModel();
    }
}

View

<Canvas x:Name="LayoutRoot" Background="White">
    <ItemsControl ItemsSource="{Binding Trainings}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <StackPanel HorizontalAlignment="Center">
                    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                        <TextBlock Text="{Binding MobileOperator}" Margin="15,15,0,0" FontWeight="Bold"/>
                        <TextBlock Text="{Binding LastUpdate, StringFormat=' - Last Updated: \{0:M/d/yy\}'}" 
                                   Margin="5,15,15,0" Foreground="Gray"/>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                        <TextBlock Text="Number trained*" />
                        <TextBox Width="50" Height="20" 
                                 Text="{Binding NumberTrained, Mode=TwoWay, ValidatesOnExceptions=True, ValidatesOnDataErrors=True}"/>
                    </StackPanel>
                </StackPanel>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
    <Button Content="ok" Width="100" Height="20" Canvas.Left="248" Canvas.Top="207" Command="{Binding OkButtonCommand}"/>
</Canvas>

I'm trying to have a TextBox's content be validated using IDataErrorInfo. The source of the list below is a List and each item is display. When i put ValidatesOnDataErrors=True in the Binding for the Text on the TextBox, it's not working as expected. How do I do this?

<ItemsControl ItemsSource="{Binding Trainings}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <StackPanel>
                    <TextBlock Text="{Binding MobileOperator}" />
                    <TextBlock Text="{Binding LastUpdate}"/>
                </StackPanel>
                <StackPanel>
                    <TextBlock Text="Number trained*" />                        
                    <!-- ValidatesOnDataErrors doesn't work here-->
                    <TextBox 
                        Text="{Binding NumberTrained, 
                                       ValidatesOnDataErrors=True}"/>
                </StackPanel>
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

Update: Posting a stripped down version of Model, ViewModel, View and CodeBehind

ViewModel and Model

public class MyViewModel : IDataErrorInfo, INotifyPropertyChanged
{
    public MyViewModel() 
    {
        Trainings = new List<MyModel>
        {
            new MyModel { NumberTrained = 5, MobileOperator = "MO 1", LastUpdate =         DateTime.Now },
            new MyModel { NumberTrained = 1, MobileOperator = "MO 2", LastUpdate = DateTime.Now },
        };

        OkButtonCommand = new ButtonCommand(OnClick);
    }

    private void OnClick()
    {
        PropertyChanged(this, new PropertyChangedEventArgs(""));
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public ICommand OkButtonCommand { get; private set; }
    public List<MyModel> Trainings { get; private set; }
    public string Error { get { return null; } }

    public string this[string columnName]
    {
        get
        {
            string error = null;
            switch (columnName)
            {
                case "NumberTrained":
                    error = "error from IDataErrorInfo";
                    break;
            }
            return error;
        }
    }
}

public class MyModel
{
    public string MobileOperator { get; set; }
    public DateTime LastUpdate { get; set; }
    public int NumberTrained { get; set; }
}

public class ButtonCommand : ICommand
{
    private Action _handler;
    public event EventHandler CanExecuteChanged;

    public ButtonCommand(Action handler) { _handler = handler; }
    public bool CanExecute(object parameter) { return true; }
    public void Execute(object parameter) { _handler(); }
}

Code Behind

public partial class MainPage : UserControl
{
    public MainPage()
    {
        InitializeComponent();

        DataContext = new MyViewModel();
    }
}

View

<Canvas x:Name="LayoutRoot" Background="White">
    <ItemsControl ItemsSource="{Binding Trainings}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <StackPanel HorizontalAlignment="Center">
                    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                        <TextBlock Text="{Binding MobileOperator}" Margin="15,15,0,0" FontWeight="Bold"/>
                        <TextBlock Text="{Binding LastUpdate, StringFormat=' - Last Updated: \{0:M/d/yy\}'}" 
                                   Margin="5,15,15,0" Foreground="Gray"/>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                        <TextBlock Text="Number trained*" />
                        <TextBox Width="50" Height="20" 
                                 Text="{Binding NumberTrained, Mode=TwoWay, ValidatesOnExceptions=True, ValidatesOnDataErrors=True}"/>
                    </StackPanel>
                </StackPanel>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
    <Button Content="ok" Width="100" Height="20" Canvas.Left="248" Canvas.Top="207" Command="{Binding OkButtonCommand}"/>
</Canvas>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

吃素的狼 2024-11-22 17:52:40

我觉得在 ViewModel 上实现 IDataErrorInfo 比在 Model 上更合适。

因此,在您的情况下,您可以创建一个额外的 ViewModel(例如:MyModelViewModel)并将其作为 List 包含在 MyViewModel 中用作 ItemsSource

通过 MVVM,如果您觉得应该有一个相应的视图,您可以将 ItemsControlDataTemplate 提取到一个新的 XMAL。

I feel implementing IDataErrorInfo on ViewModel is more appropriate rather than on Model.

So in your case, you could have created an additional ViewModel (ex: MyModelViewModel) and include it as a List<MyModelViewModel> inside MyViewModel to be used as the ItemsSource.

Going by MVVM, if you feel you should have a corresponding View for it, you can extract out the DataTemplate of the ItemsControl to a new XMAL.

临走之时 2024-11-22 17:52:40

您需要在模型上实现 IDataErrorInfo,而不是 ViewModel。

现在,当您尝试验证不存在的属性 MyViewModel.NumberTrained 时,您的验证检查会抛出错误,因此验证错误永远不会被调用。

You need to implement IDataErrorInfo on your Model, not your ViewModel.

As it is right now, your a validation check is throwing an error when you try and validate the property MyViewModel.NumberTrained, which doesn't exist, so the validation error never gets called.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文