locked
Passing CommandParameter works on WPF CanDoLogin but it doesn't work on Windows 8.1 Store

    Question

  • I'm developing a Windows 8.1 store app with C#, .NET Framework 4.5.1 and MVVM Light Framework.

    I'm trying to pass a PasswordBox as a parameter on a button Command. I've tested the following code on WPF and it works.

    MainViewModel class:
       public class MainViewModel : ViewModelBase
        {
            private RelayCommand<PasswordBox> doLoginCommand;
        
            /// <summary>
            /// The <see cref="UserName" /> property's name.
            /// </summary>
            public const string UserNamePropertyName = "UserName";
        
            private string _userName = string.Empty;
        
            /// <summary>
            /// Sets and gets the UserName property.
            /// Changes to that property's value raise the PropertyChanged event.
            /// </summary>
            public string UserName
            {
                get
                {
                    return _userName;
                }
                set
                {
                    Set(UserNamePropertyName, ref _userName, value);
                }
            }
        
            /// <summary>
            ///
            /// </summary>
            public RelayCommand<PasswordBox> DoLoginCommand
            {
                get { return doLoginCommand; }
            }
        
            /// <summary>
            /// Initializes a new instance of the MainViewModel class.
            /// </summary>
            public MainViewModel()
            {
                ////if (IsInDesignMode)
                ////{
                ////    // Code runs in Blend --> create design time data.
                ////}
                ////else
                ////{
                ////    // Code runs "for real"
                ////}
        
                this.doLoginCommand = new RelayCommand<PasswordBox>((pb) => ExecuteDoLogin(pb), (pb) => CanDoLogin(pb));
                //this.doLoginCommand = new RelayCommand<PasswordBox>((pb) => ExecuteDoLogin(pb));
            }
        
            private void ExecuteDoLogin(object parameter)
            {
                PasswordBox passwordBox = parameter as PasswordBox;
                Debug.WriteLine(_userName);
                Debug.WriteLine(passwordBox.Password);
            }
        
            private bool CanDoLogin(object parameter)
            {
                Debug.WriteLine("CanDoLogin");
                PasswordBox passwordBox = parameter as PasswordBox;
                return ((!string.IsNullOrEmpty(_userName)) &&
                    (!string.IsNullOrEmpty(passwordBox.Password)));
            }
        }
    And its View:
     <Page
            x:Class="MyProject.W81.MainPage"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="using:MyProject.W81"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            DataContext="{Binding MainViewModel, Source={StaticResource Locator}}"
            mc:Ignorable="d">
        
            <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="33*"/>
                    <ColumnDefinition Width="77*"/>
                </Grid.ColumnDefinitions>
                <StackPanel Grid.Column="1" HorizontalAlignment="Center" Height="400" Margin="0" VerticalAlignment="Center" Width="600">
                    <TextBox
                        x:Name="userName"
                        TextWrapping="Wrap"
                        HorizontalAlignment="Left"
                        VerticalAlignment="Top"
                        Text="{Binding UserName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                        Width="247"
                        Margin="10,10,10,5"/>
                    <PasswordBox
                        x:Name="userPassword"
                        HorizontalAlignment="Left"
                        VerticalAlignment="Top"
                        Width="250"
                        FontFamily="Global User Interface"
                        Margin="10,5"/>
                    <Button
                        x:Name="loginButton"
                        Content="Login"
                        HorizontalAlignment="Left"
                        VerticalAlignment="Stretch"
                        Command="{Binding DoLoginCommand}"
                        CommandParameter="{Binding ElementName=userPassword}"
                        Margin="10,5" />
                </StackPanel>
            </Grid>
        </Page>
    But on Windows 8.1 it doesn't work. The problem is that `loginButton` is always disabled because CanDoLogin never runs. I have add a log in that method and it only runs twice when I do:
    this.doLoginCommand = new RelayCommand<PasswordBox>((pb) => ExecuteDoLogin(pb), (pb) => CanDoLogin(pb));


    I have removed CanDoLogin on doLoginCommand creation and I can get _userName and userPassword.Password values.

    Any advice? Do you know why `loginButton` is always disabled?
    • Edited by VansFannel Tuesday, October 7, 2014 7:14 AM
    Tuesday, October 7, 2014 7:14 AM

Answers

  • loginButton is always disabled because CanDoLogin returned false when it was called at page load time.  This makes sense because at page load the password is empty.

    register for the PasswordChanged event:

                <PasswordBox
                        x:Name="userPassword"
                        HorizontalAlignment="Left"
                        VerticalAlignment="Top"
                        Width="250"
                        FontFamily="Global User Interface"
                        Margin="10,5"
                    PasswordChanged="userPassword_PasswordChanged"/>



    In that event fire the RaiseCanExecuteChanged() Event on your command:

            private void userPassword_PasswordChanged(object sender, RoutedEventArgs e)
            {
                //  Cause CanExecuteChanged to be called
                MainViewModel mvm = (MainViewModel)this.DataContext;
                mvm.DoLoginCommand.RaiseCanExecuteChanged();
            }


    Bret Bentzinger (MSFT) @awehellyeah

    Tuesday, October 7, 2014 10:33 PM
    Moderator