Björn
Björn

Reputation: 3418

How do I disable some controls based on validation in WPF?

I have a WPF application which consists of a TabControl. I have made a simple version of it for the purpose of this question:

enter image description here

In the first tab I have combobox which fills a datagrid. If I selected a row in the datagrid it gets bound a couple of textboxes and the user may edit its contents.

My objects in the datagrid implements the IDataErrorInfo interface and my textboxes has ValidatesOnDataErrors=True set in the {binding}. So if I erase the contents of the Name textbox it gets invalid (after the textbox loses focus):

enter image description here

Now, if it is invalid I don't want the user to be able to select another row in the datagrid, or select another row in the combobox (which would repopulate the datagrid). Basically I want the user to correct the name before he/she continues. Although, I would prefer if the user could switch tab.

So I either need to disable the controls to the left if the bound object is invalid or I need to set focus to the invalid textbox if I click on the controls to the left. I havn't found any suitable events or bindings for this. All ideas are appreciated.

Here is my 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>

And here is the code behind:

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));
        }
    }
}

Upvotes: 2

Views: 3049

Answers (1)

Ankesh
Ankesh

Reputation: 4885

You can use a trigger to disable the control

     <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>

Upvotes: 3

Related Questions