none
Enable/Disable button in MainWindow using RelayCommand depending on status of TextBox in UserControl RRS feed

  • Question

  • Hi!

    I am building a new LOB and the app is going to have a standard layout (like the Outlook, with buttons on left and ribbons).

    When the user wants to do something i replace the content in my ContentControl with a UserControl.

    Now when that user control is active i want a couple of buttons in the ribbon to use the CanExecute using binding on the controls inside the UserControl (i.e. textbox grids etc)

    But how do i bind the Command and CanExecute to controls inside a UserControl VM (ViewModel) from the MainWindow? And ofcourse when the User Control is replaced with another i want to disable the buttons.

    I just cant figure this out. Within the same window I know how to do it.

    (Off subject, is using a UserControl the right way to go for having, lets say, Customer view, order view etc)

    Regards
    Martin


    • Edited by Datamartin Tuesday, April 7, 2015 8:17 AM My previsous question was not correctly asked. I do want to know on how to bind command to a control within the UserControl ie textbox to my ViewModel
    Thursday, April 2, 2015 10:54 AM

Answers

  • Hi Datamartin,

    >>” how do i bind the Command and CanExecute to the UserControl VM (ViewModel) from the MainWindow?”

    In my experience,the UserControl has no Command ,so if you want to bind command to UserControl,you need to define the command dependency property of your custom UserControl.

    I made a code sample for you,the  RelayCommand class implemented the ICommand interface,and the UserControl1 defined the Command dependency property etc.In the UserControl1,it will trigger the Execute method of command when the Textbox textchanged and lostfocused.

    public class RelayCommand : ICommand
        {
            #region Fields
    
            readonly Action<object> _execute;
            readonly Predicate<object> _canExecute;
    
            #endregion // Fields
    
            #region Constructors
    
            public RelayCommand(Action<object> execute)
                : this(execute, null)
            {
            }
    
            public RelayCommand(Action<object> execute, Predicate<object> canExecute)
            {
                if (execute == null)
                    throw new ArgumentNullException("execute");
    
                _execute = execute;
                _canExecute = canExecute;
            }
            #endregion // Constructors
    
            #region ICommand Members
    
            public bool CanExecute(object parameter)
            {
                return _canExecute == null ? true : _canExecute(parameter);
            }
    
            public event EventHandler CanExecuteChanged
            {
                add { CommandManager.RequerySuggested += value; }
                remove { CommandManager.RequerySuggested -= value; }
            }
    
            public void Execute(object parameter)
            {
                _execute(parameter);
            }
    
            #endregion // ICommand Members
    }

    The UserControl1.cs

    public partial class UserControl1 : UserControl,ICommandSource
        {
            public UserControl1()
            {
                InitializeComponent();
            }
    
            public static readonly DependencyProperty CommandProperty =
                DependencyProperty.Register("Command", typeof(ICommand), typeof(UserControl1), new UIPropertyMetadata(null));
    
            public ICommand Command
            {
                get { return (RelayCommand)GetValue(CommandProperty); }
                set { SetValue(CommandProperty, value); }
            }
    
            public IInputElement CommandTarget
            {
                get;
                set;
            }
    
            public object CommandParameter
            {
                get { return (object)GetValue(CommandParameterProperty); }
                set { SetValue(CommandParameterProperty, value); }
            }
            
    
            // Using a DependencyProperty as the backing store for CommandParameter.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty CommandParameterProperty =
                DependencyProperty.RegisterAttached("CommandParameter", typeof(object), typeof(UserControl1), new PropertyMetadata());
    
    
    
            public bool IsMyFocused
            {
                get { return (bool)GetValue(IsMyFocusedProperty); }
                set { SetValue(IsMyFocusedProperty, value); }
            }
    
            // Using a DependencyProperty as the backing store for IsMyFocused.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty IsMyFocusedProperty =
                DependencyProperty.Register("IsMyFocused", typeof(bool), typeof(UserControl1), new PropertyMetadata(false));
    
            private void txb_TextChanged(object sender, TextChangedEventArgs e)
            {
                this.IsMyFocused = true;
                if(this.Command != null)
                {
                    this.Command.Execute(this.CommandParameter);
                }
                
            }
    
            private void txb_LostFocus(object sender, RoutedEventArgs e)
            {
                this.IsMyFocused = false;
                if (this.Command != null)
                {
                    this.Command.Execute(this.CommandParameter);
                }
            }
    
            
        }
    The MainViewModel.cs
    public class MainViewModel
        {
            public RelayCommand btnStateCommand { get; set; }
            public MainViewModel()
            {
                btnStateCommand = new RelayCommand(ButtonState);
            }
    
            protected void ButtonState(object sender)
            { 
                if(sender != null)
                {
                    StackPanel st = (StackPanel)sender;
                    var usercontrol = st.FindName("UserControl");
                    var btn = st.FindName("btn");
                    if(usercontrol != null && btn != null)
                    {
                        UserControl1 myusercontrol = usercontrol as UserControl1;
                        Button button = btn as Button;
                        if (myusercontrol.IsMyFocused)
                        {
                            button.IsEnabled = true;
                        }
                        else
                        {
                            button.IsEnabled = false;
                        }
                    }
                }
            }
        }
    The MainWindow xaml:
    <Window x:Class="WpfAppUserControl.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfAppUserControl"
            xmlns:mainViewmodel="clr-namespace:WpfAppUserControl.ViewModel"
            Title="MainWindow" Height="350" Width="525"
            DataContext="{DynamicResource mainviewmodel}">
        <Window.Resources>
            <mainViewmodel:MainViewModel x:Key="mainviewmodel"></mainViewmodel:MainViewModel>
        </Window.Resources>
        <StackPanel x:Name="st">
            <local:UserControl1 x:Name="UserControl" Width="100" Height="30" Command="{Binding btnStateCommand}" CommandParameter="{Binding ElementName=st}"></local:UserControl1>
            <Button Width="80" Height="50" Content="button" x:Name="btn" ></Button>
        </StackPanel>
    </Window>

    • Edited by messizhu Tuesday, April 7, 2015 8:19 AM
    • Marked as answer by Datamartin Thursday, April 9, 2015 8:57 AM
    Tuesday, April 7, 2015 3:14 AM
  • Hi Datamartin,

    In my experience,if you want to bind command to the textbox,you need to define command dependency property,then you could bind command to it.It’s the same with defining command dependency property of UserControl1.

    Based on your question,I suggested you need to learn about DependencyProperty and Command in WPF,then you will know why I do it.

    You could refer to DependencyProperty Class document for details: https://msdn.microsoft.com/en-us/library/vstudio/system.windows.dependencyproperty(v=vs.100).aspx
    Commanding Overview: https://msdn.microsoft.com/en-us/library/ms752308(v=vs.110).aspx

    Best regards,

    Eoro

    • Marked as answer by Datamartin Thursday, April 9, 2015 8:57 AM
    Tuesday, April 7, 2015 9:54 AM

All replies

  • Hi Datamartin,

    >>” how do i bind the Command and CanExecute to the UserControl VM (ViewModel) from the MainWindow?”

    In my experience,the UserControl has no Command ,so if you want to bind command to UserControl,you need to define the command dependency property of your custom UserControl.

    I made a code sample for you,the  RelayCommand class implemented the ICommand interface,and the UserControl1 defined the Command dependency property etc.In the UserControl1,it will trigger the Execute method of command when the Textbox textchanged and lostfocused.

    public class RelayCommand : ICommand
        {
            #region Fields
    
            readonly Action<object> _execute;
            readonly Predicate<object> _canExecute;
    
            #endregion // Fields
    
            #region Constructors
    
            public RelayCommand(Action<object> execute)
                : this(execute, null)
            {
            }
    
            public RelayCommand(Action<object> execute, Predicate<object> canExecute)
            {
                if (execute == null)
                    throw new ArgumentNullException("execute");
    
                _execute = execute;
                _canExecute = canExecute;
            }
            #endregion // Constructors
    
            #region ICommand Members
    
            public bool CanExecute(object parameter)
            {
                return _canExecute == null ? true : _canExecute(parameter);
            }
    
            public event EventHandler CanExecuteChanged
            {
                add { CommandManager.RequerySuggested += value; }
                remove { CommandManager.RequerySuggested -= value; }
            }
    
            public void Execute(object parameter)
            {
                _execute(parameter);
            }
    
            #endregion // ICommand Members
    }

    The UserControl1.cs

    public partial class UserControl1 : UserControl,ICommandSource
        {
            public UserControl1()
            {
                InitializeComponent();
            }
    
            public static readonly DependencyProperty CommandProperty =
                DependencyProperty.Register("Command", typeof(ICommand), typeof(UserControl1), new UIPropertyMetadata(null));
    
            public ICommand Command
            {
                get { return (RelayCommand)GetValue(CommandProperty); }
                set { SetValue(CommandProperty, value); }
            }
    
            public IInputElement CommandTarget
            {
                get;
                set;
            }
    
            public object CommandParameter
            {
                get { return (object)GetValue(CommandParameterProperty); }
                set { SetValue(CommandParameterProperty, value); }
            }
            
    
            // Using a DependencyProperty as the backing store for CommandParameter.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty CommandParameterProperty =
                DependencyProperty.RegisterAttached("CommandParameter", typeof(object), typeof(UserControl1), new PropertyMetadata());
    
    
    
            public bool IsMyFocused
            {
                get { return (bool)GetValue(IsMyFocusedProperty); }
                set { SetValue(IsMyFocusedProperty, value); }
            }
    
            // Using a DependencyProperty as the backing store for IsMyFocused.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty IsMyFocusedProperty =
                DependencyProperty.Register("IsMyFocused", typeof(bool), typeof(UserControl1), new PropertyMetadata(false));
    
            private void txb_TextChanged(object sender, TextChangedEventArgs e)
            {
                this.IsMyFocused = true;
                if(this.Command != null)
                {
                    this.Command.Execute(this.CommandParameter);
                }
                
            }
    
            private void txb_LostFocus(object sender, RoutedEventArgs e)
            {
                this.IsMyFocused = false;
                if (this.Command != null)
                {
                    this.Command.Execute(this.CommandParameter);
                }
            }
    
            
        }
    The MainViewModel.cs
    public class MainViewModel
        {
            public RelayCommand btnStateCommand { get; set; }
            public MainViewModel()
            {
                btnStateCommand = new RelayCommand(ButtonState);
            }
    
            protected void ButtonState(object sender)
            { 
                if(sender != null)
                {
                    StackPanel st = (StackPanel)sender;
                    var usercontrol = st.FindName("UserControl");
                    var btn = st.FindName("btn");
                    if(usercontrol != null && btn != null)
                    {
                        UserControl1 myusercontrol = usercontrol as UserControl1;
                        Button button = btn as Button;
                        if (myusercontrol.IsMyFocused)
                        {
                            button.IsEnabled = true;
                        }
                        else
                        {
                            button.IsEnabled = false;
                        }
                    }
                }
            }
        }
    The MainWindow xaml:
    <Window x:Class="WpfAppUserControl.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfAppUserControl"
            xmlns:mainViewmodel="clr-namespace:WpfAppUserControl.ViewModel"
            Title="MainWindow" Height="350" Width="525"
            DataContext="{DynamicResource mainviewmodel}">
        <Window.Resources>
            <mainViewmodel:MainViewModel x:Key="mainviewmodel"></mainViewmodel:MainViewModel>
        </Window.Resources>
        <StackPanel x:Name="st">
            <local:UserControl1 x:Name="UserControl" Width="100" Height="30" Command="{Binding btnStateCommand}" CommandParameter="{Binding ElementName=st}"></local:UserControl1>
            <Button Width="80" Height="50" Content="button" x:Name="btn" ></Button>
        </StackPanel>
    </Window>

    • Edited by messizhu Tuesday, April 7, 2015 8:19 AM
    • Marked as answer by Datamartin Thursday, April 9, 2015 8:57 AM
    Tuesday, April 7, 2015 3:14 AM
  • Hi!

    Thanx for your reply. I feel so stupid but what I meant was to bind to a control within the usercontrol.

    I saw what i had written and it was not the correct description of the problem, so sorry

    I will corrictify my question...

    But perhaps its the same way anyhow...

    Tuesday, April 7, 2015 8:15 AM
  • Hi Datamartin,

    In my experience,if you want to bind command to the textbox,you need to define command dependency property,then you could bind command to it.It’s the same with defining command dependency property of UserControl1.

    Based on your question,I suggested you need to learn about DependencyProperty and Command in WPF,then you will know why I do it.

    You could refer to DependencyProperty Class document for details: https://msdn.microsoft.com/en-us/library/vstudio/system.windows.dependencyproperty(v=vs.100).aspx
    Commanding Overview: https://msdn.microsoft.com/en-us/library/ms752308(v=vs.110).aspx

    Best regards,

    Eoro

    • Marked as answer by Datamartin Thursday, April 9, 2015 8:57 AM
    Tuesday, April 7, 2015 9:54 AM