简体   繁体   中英

MVVM WPF Multibinding is not working for command parameters

I cannot make multibinding working for two passwordbox. I did read a bunch of articles on the net tried working examples, but none of them was the same scenario that I've tried. The problem is when I hit the login button then these password fields are not transfered to the command Execute method.

XAML for the converter:

<Grid.Resources>
    <converter:PasswordConverter x:Key="passwordConverter"/>
</Grid.Resources>

XAML for the button looks like this:

<Button x:Name="loginButton" 
                Content="Belépés" 
                Margin="494,430,0,0" 
                VerticalAlignment="Top" 
                FontSize="20" 
                RenderTransformOrigin="-2.624,8.99" 
                HorizontalAlignment="Left" 
                Width="172"
                Command="{Binding NavCommand}">
            <Button.CommandParameter>
                <MultiBinding Converter="{StaticResource passwordConverter}" Mode="TwoWay">
                    <Binding Path="Password" ElementName="userIDPasswordBox"/>
                    <Binding Path="Password" ElementName="leaderIDPasswordBox"/>
                </MultiBinding>
            </Button.CommandParameter>
        </Button>

Password converter code:

public class PasswordConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        return values.Clone();
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Relay command:

public class RelayCommand : ICommand
{

    Action _TargetExecuteMethod;
    Func<bool> _TargetCanExecuteMethod;

    public RelayCommand(Action executeMethod)
    {
        _TargetExecuteMethod = executeMethod;
    }

    public RelayCommand(Action executeMethod, Func<bool> canExecuteMethod)
    {
        _TargetExecuteMethod = executeMethod;
        _TargetCanExecuteMethod = canExecuteMethod;
    }

    public void RaiseCanExecuteChanged()
    {
        CanExecuteChanged(this, EventArgs.Empty);
    }

    #region ICommand Members

    bool ICommand.CanExecute(object parameter)
    {

        if (_TargetCanExecuteMethod != null)
        {
            return _TargetCanExecuteMethod();
        }

        if (_TargetExecuteMethod != null)
        {
            return true;
        }

        return false;
    }

    public event EventHandler CanExecuteChanged = delegate { };

    void ICommand.Execute(object parameter)
    {
        if (_TargetExecuteMethod != null)
        {
            _TargetExecuteMethod();
        }
    }

    #endregion
}

and last huge piece of code for the view model:

public class LogonViewModel : BaseViewModel
{

private Action _loginActionComplete;
public LogonViewModel(Action loginActionComplete)
{
    _measureTimer = new Timer();
    _measureTimer.Interval = 500D;
    _measureTimer.Elapsed += measureTimer_Elapsed;
    _measureTimer.Start();
    _loginActionComplete = loginActionComplete;
    NavCommand = new RelayCommand(loginActionComplete);
    SerialPort = new SerailCommunicationNameSpace.SerialCommunication("COM3");
}

~LogonViewModel()
{
    SerialPort.Close();
}

public RelayCommand NavCommand { get; private set; }

private double _measuredWeight;
public double MeasuredWeight {
    get
    {
        return _measuredWeight;
    }
    set
    {
        SetProperty(ref _measuredWeight, value);
    }
}
private Timer _measureTimer;
public SerailCommunicationNameSpace.SerialCommunication SerialPort { get; set; }

private void measureTimer_Elapsed(object sender, ElapsedEventArgs e)
{
    var measuredWeight = 0D;
    if (string.IsNullOrWhiteSpace(SerialPort.DataReceived) == false) {
        var dataReceivedStartTrim = SerialPort.DataReceived.TrimStart();
        var dataReceivedNumbersOnly = dataReceivedStartTrim.Substring(0, dataReceivedStartTrim.IndexOf(' '));
        var enUSCultureInfo = new CultureInfo("en-US");
        measuredWeight = double.Parse(dataReceivedNumbersOnly, enUSCultureInfo);
    }
    SetProperty(ref _measuredWeight, measuredWeight);
    OnPropertyChanged("MeasuredWeight");
}

public string LeaderId { get; set; }

public string UserId { get; set; }

}

The problem is that Password property of PasswordBox is neither a dependency property nor implements INotifyPropertyChanged . This means, that the changes of password will not be applied to the binding.
Eg if you add an event handler for PasswordChanged to the PasswordBox and set the password to the Tag property, then you can bind to the Tag and the binding will work.

<Button x:Name="loginButton" 
        Content="Belépés" 
        Margin="494,430,0,0" 
        VerticalAlignment="Top" 
        FontSize="20" 
        RenderTransformOrigin="-2.624,8.99" 
        HorizontalAlignment="Left" 
        Width="172"
        Command="{Binding NavCommand}">
    <Button.CommandParameter>
        <MultiBinding Converter="{StaticResource passwordConverter}">
            <Binding Path="Tag" ElementName="userIDPasswordBox"/>
            <Binding Path="Tag" ElementName="leaderIDPasswordBox"/>
        </MultiBinding>
    </Button.CommandParameter>
</Button>

<PasswordBox Name="userIDPasswordBox" PasswordChanged="PasswordBox_PasswordChanged"/>
<PasswordBox Name="leaderIDPasswordBox" PasswordChanged="PasswordBox_PasswordChanged"/>

private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
{
    var pbx = sender as PasswordBox;
    if (pbx!=null)
    {
        pbx.Tag = pbx.Password;
    }
}

Of course to avoid code behind implementation you should move the event handler to the behavior.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM