如何在WPF中禁用一些基于验证的控件?

如何在WPF中禁用一些基于验证的控件?,wpf,validation,focus,Wpf,Validation,Focus,我有一个WPF应用程序,它由一个TabControl组成。为了回答这个问题,我做了一个简单的版本: 在第一个选项卡中,我有一个填充数据网格的组合框。如果我在datagrid中选择了一行,它会绑定几个文本框,用户可以编辑它的内容 datagrid中的My对象实现IDataErrorInfo接口,我的文本框在{binding}中设置了validateOnDaerRors=True。因此,如果我删除名称文本框的内容,它将变得无效(在文本框失去焦点后): 现在,如果无效,我不希望用户能够在datag

我有一个WPF应用程序,它由一个TabControl组成。为了回答这个问题,我做了一个简单的版本:

在第一个选项卡中,我有一个填充数据网格的组合框。如果我在datagrid中选择了一行,它会绑定几个文本框,用户可以编辑它的内容

datagrid中的My对象实现IDataErrorInfo接口,我的文本框在{binding}中设置了validateOnDaerRors=True。因此,如果我删除名称文本框的内容,它将变得无效(在文本框失去焦点后):

现在,如果无效,我不希望用户能够在datagrid中选择另一行,或者在combobox中选择另一行(这将重新填充datagrid)。基本上,我希望用户在继续之前更正名称。尽管如此,我还是希望用户可以切换选项卡

因此,如果绑定对象无效,我需要禁用左侧的控件;如果单击左侧的控件,我需要将焦点设置为无效文本框。我还没有找到任何合适的活动或绑定。非常感谢所有想法

这是我的XAML:

<Window x:Class="WpfValidationTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="350">
    <TabControl>
        <TabItem Header="Tab 1">
            <StackPanel Orientation="Horizontal">
                <StackPanel Orientation="Vertical">
                    <ComboBox>
                        <ComboBox.Items>
                            <ComboBoxItem Content="Friends"/>
                            <ComboBoxItem Content="Business"/>
                        </ComboBox.Items>
                    </ComboBox>
                    <DataGrid Name="dg" AutoGenerateColumns="False">
                        <DataGrid.Columns>
                            <DataGridTextColumn Header="Name" Binding="{Binding Name}" />
                            <DataGridTextColumn Header="Address" Binding="{Binding Address}" />
                        </DataGrid.Columns>
                    </DataGrid>
                </StackPanel>

                <StackPanel Orientation="Vertical" Width="200" Margin="10,0,0,0">
                    <TextBlock Text="Edit" FontWeight="Bold"/>
                    <TextBlock Text="Name:"/>
                    <TextBox Text="{Binding Path=SelectedItem.Name, ElementName=dg, ValidatesOnDataErrors=True}" />
                    <TextBlock Text="Address:"/>
                    <TextBox Text="{Binding Path=SelectedItem.Address, ElementName=dg, ValidatesOnDataErrors=True}" />
                </StackPanel>
            </StackPanel>
        </TabItem>

        <TabItem Header="Tab 2">
            <TextBlock Text="The user should be able to navigate to this tab even if there are validation errors" TextWrapping="Wrap" />
        </TabItem>
    </TabControl>

</Window>

下面是背后的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;

namespace WpfValidationTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            List<Person> persons = new List<Person>()
            {
                new Person(){Name="John Doe", Address="My street 203"},
                new Person(){Name="Jane Doe", Address="Your street 43"}
            };
            dg.ItemsSource = persons;
        }
    }

    public class Person : INotifyPropertyChanged, IDataErrorInfo
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public string Error
        {
            get { throw new NotImplementedException(); }
        }

        public string this[string columnName]
        {
            get 
            {
                switch (columnName)
                {
                    case "Name":
                        if (string.IsNullOrEmpty(Name))
                            return "Name must be entered";
                        break;
                    case "Address":
                        if (string.IsNullOrEmpty(Address))
                            return "Address must be entered";
                        break;
                }
                return null;
            }
        }

        private string _name;
        public string Name
        {
            get { return _name; }
            set
            {
                _name = value;
                NotifyPropertyChanged("Name");
            }
        }

        private string _address;
        public string Address
        {
            get { return _address; }
            set
            {
                _address = value;
                NotifyPropertyChanged("Address");
            }
        }

        private void NotifyPropertyChanged(string propName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Windows;
使用System.Windows.Controls;
使用System.Windows.Data;
使用System.Windows.Documents;
使用System.Windows.Input;
使用System.Windows.Media;
使用System.Windows.Media.Imaging;
使用System.Windows.Navigation;
使用System.Windows.Shapes;
使用系统组件模型;
命名空间WpfValidationTest
{
/// 
///MainWindow.xaml的交互逻辑
/// 
公共部分类主窗口:窗口
{
公共主窗口()
{
初始化组件();
名单人员=新名单()
{
新人(){Name=“John Doe”,Address=“My street 203”},
新人(){Name=“Jane Doe”,Address=“Your street 43”}
};
dg.ItemsSource=人员;
}
}
公共类人员:INotifyPropertyChanged,IDataErrorInfo
{
公共事件属性更改事件处理程序属性更改;
公共字符串错误
{
获取{抛出新的NotImplementedException();}
}
公共字符串此[string columnName]
{
得到
{
开关(列名称)
{
案例“名称”:
if(string.IsNullOrEmpty(Name))
return“必须输入名称”;
打破
案例“地址”:
if(string.IsNullOrEmpty(Address))
返回“必须输入地址”;
打破
}
返回null;
}
}
私有字符串\u名称;
公共字符串名
{
获取{return\u name;}
设置
{
_名称=值;
NotifyPropertyChanged(“名称”);
}
}
私有字符串地址;
公共字符串地址
{
获取{return\u address;}
设置
{
_地址=值;
NotifyPropertyChanged(“地址”);
}
}
私有void NotifyPropertyChanged(字符串propName)
{
if(PropertyChanged!=null)
PropertyChanged(这是新PropertyChangedEventArgs(propName));
}
}
}

您可以使用触发器禁用控件

     <Style x:Key="disableOnValidation"
           BasedOn="{StaticResource {x:Type DataGrid}}"
           TargetType="{x:Type DataGrid}">
        <Style.Triggers>
            <DataTrigger Binding="{Binding ElementName=nameTextBox, Path=Validation.HasError}" Value="True">
                <Setter Propert="IsEnabled" Value="False" />
            </DataTrigger>
            <DataTrigger Binding="{Binding ElementName=addressTextbox, Path=Validation.HasError}" Value="True">
                <Setter Propert="IsEnabled" Value="False" />
            </DataTrigger>
        </Style.Triggers>
    </Style>


感谢Merlyn Morgan Graham添加这些图像。由于我是一名新会员,所以无法添加。谢谢adcool2007,它几乎成功了。我必须将绑定路径更改为(Validation.HasError),正如本文所述:另一个问题是,当IsEnabled设置为false时,datagrid的SelectedItem变为null。所以我改成了这样:用户可能仍然会在datagrid中使用tab键:-(@Björn您是否将SelectedItemin datagrid的绑定设置为Viewmodel属性,如
SelectedItem={binding Path=MySelectedItem,Mode=TwoWay}
?我的简单示例中没有使用viewmodel,但我现在制作了一个viewmodel来尝试绑定表达式,但我仍然遇到相同的问题:当datagrid被禁用时,SelectedItem被设置为null,这使得我在viewmodel中的属性也为null。如果我将IshittesVisible设置为“False”,则不透明度设置为“0.5”和KeyboardNavigation.TabNavigation在数据触发器中设置为“无”,然后我会得到一个近似等于禁用datagrid的结果。我会将adcool2007的答案标记为已接受,因为他/她引导了我。谢谢。