0

I have the next scenario: A view with a tabControl and a button:

<Window x:Class="some"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        
    Title="Settings" Height="412" Width="586"
    DataContext="{Binding SettingsViewModel}">
<Grid>
    ...
    <TabControl Name="TabControlSettings" Grid.Row="0" Grid.ColumnSpan="3" Margin="10, 10, 10, 10">            
        <TabItem Header="settings1">                
        ...
        </TabItem>
        <TabItem Header="settings1">
        ...
        </TabItem>
        <TabItem Header="settings2">
         ...
        </TabItem>
        <TabItem Header="settings3">
        ...
        </TabItem>
        <TabItem Header="settings3">
        ...            
        </TabItem>
    </TabControl>
    <Button Grid.Row="1" Grid.Column="2" Name="btn_Ok" Content="Ok" HorizontalAlignment="Left" Width="50" Height="23" Margin="10"  Command="{Binding SaveSettingsCommand}" Click="btn_Ok_Click" />       

</Grid>

some UI validations are catched in the btn_Ok_Click event defined in the code behind:

private void btn_Ok_Click(object sender, RoutedEventArgs e)
    {
        bool HasErrors = false;

        HasErrors = !ViewServices.IsValid(TabControlSettings);
        if (HasErrors)
        {
            var control = ViewServices.controlToValidate.Values.First() as System.Windows.Controls.Control;
            control.Focus();
        }
        else
        { 
            this.Close();
        }            
    }

ViewServices is just a helper class that provides some methods for the Views as is the case of IsValid:

 public static Dictionary<bool, object> controlToValidate;


    /// <summary>
    /// validates all binding rules on a dependency object and its children:
    /// </summary>
    /// <param name="obj">Dependency object</param>
    /// <returns>True if none of the child objects has errors, False otherwise</returns>
    internal static bool IsValid(DependencyObject parent) 
    {
        controlToValidate = new Dictionary<bool, object>();
        // The dependency object is valid if it has no errors,
        //and all of its children (that are dependency objects) are error-free.
        if (Validation.GetHasError(parent))
        {
            var obj = GetTabItem(parent);
            controlToValidate.Add(false, obj);             
            return false;
        }
        foreach (DependencyObject child in LogicalTreeHelper.GetChildren(parent).OfType<DependencyObject>())
        {
            if (!IsValid(child))
            {
                if (controlToValidate.Count == 0)
                {
                    var obj = GetTabItem(child);
                    controlToValidate.Add(false, obj);                        
                }
                return false;
            }
        }
        return true;            
    } 

    internal static object GetTabItem(DependencyObject obj)
    {
        var parent = LogicalTreeHelper.GetParent(obj);
        var parentControl = parent as System.Windows.Controls.Control;
        if (parentControl != null)
        {
            if (parentControl.GetType() != typeof(System.Windows.Controls.TabItem))
            {
                return GetTabItem(parent);
            }
            else
                return parentControl;
        }
        else
        {
            return GetTabItem(parent);
        }               
    }

With this method I get the tabitem containing controls with validation errors.

Now again returning to the btn_OK_Click event in the code behind:

HasErrors = !ViewServices.IsValid(TabControlSettings);
        if (HasErrors)
        {
            var control = ViewServices.controlToValidate.Values.First() as System.Windows.Controls.Control;
            control.Focus();
        }
        else
        { 
            this.Close();
        }

I have noticed that the Click event of the button is invoked before the command binded to the button (am I right?).

I want to avoid the execution of the SaveSettingsCommand if HasErrors is true. how can that be done?

jortizromo
  • 806
  • 9
  • 20
  • 3
    Isn't this what the CanExecute event is designed for? – Matt Burland Apr 03 '12 at 15:38
  • Although I don't know if changing the state of CanExecute in the Click event will actually prevent the Command from running; if that doesn't work, can't your Command.Execute event just do nothing? – Michael Edenfield Apr 03 '12 at 15:53
  • Why are you using code behind instead of binding your buttons to commands? – benjgorman Apr 03 '12 at 16:16
  • The code behind is only to keep the focus on the TabItem that contains child controls with validation Errors and that basically implements the solution shown here: [View link](http://stackoverflow.com/questions/127477/detecting-wpf-validation-errors) and in fact the button is binded to the SaveSettingsCommand that I want to avoid the execution if there are still validation errors in the controls. Sorry I am just new in WPF and MvvM, I just dont know how to set the CanExecute to false, and if that will work. – jortizromo Apr 03 '12 at 16:37

1 Answers1

0

Maybe it will help you to take a look at how I disable a button using Validations when HasErrors equals true.

http://www.wpfsharp.com/2012/02/03/how-to-disable-a-button-on-textbox-validationerrors-in-wpf/

Rhyous
  • 6,510
  • 2
  • 44
  • 50