Можно ли передать экземпляр класса в параметр команды?

Можно ли передать экземпляр класса в параметр команды?

ViewModel

 public class RegLeftViewModel : ViewModelBase
    {
        public EmailContainer RegEmailContainer { get; } = new EmailContainer() { Email = "", Code = 0 };


        Random random = new Random();

        private int code;

        private string regEmailEntered = "";

        
        public string RegEmailEntered
        {
            get => regEmailEntered;
            set => Set(ref regEmailEntered, value);
        }

        private string regLoginEntered;

        public string RegLoginEntered
        {
            get => regLoginEntered;
            set {
                code = random.Next(1000, 9999);
                RegEmailContainer.Code = code;
                Set(ref regLoginEntered, value);
                RegEmailContainer.Email = value;
                    }
        }

        private string regPasswordEntered;

        public RegLeftViewModel()
        {
            SendEmailCommand = new SendEmailCommand();
            RegCommand = new LambdaCommand(OnRegCommandExecuted, CanRegCommandExecute);
            
        }

        public string RegPasswordEntered
        {
            get => regPasswordEntered;
            set => Set(ref regPasswordEntered, value);
        }

        private bool IfPasswordRight = false;

        private bool IfCodeRight { get; set; }

        public ICommand SendEmailCommand { get; }

        public ICommand RegCommand { get; }

        public void OnRegCommandExecuted(object p)
        {
            DB.Reg(RegLoginEntered, RegPasswordEntered, RegEmailEntered);
        }

        public bool CanRegCommandExecute(object p) => !DB.IfLoginCreated(RegLoginEntered) && IfPasswordRight && IfCodeRight;








    }

XAML

<UserControl x:Class="FinalWPFApp.Views.LogReg.RegLeftView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:FinalWPFApp.Views.LogReg"
             mc:Ignorable="d" 
                Width="522" Height="500" Background="Transparent"
             FontWeight="Light">
    <Grid>
        <Border
               BorderThickness="2"
               CornerRadius="40"
               Margin="50, 55, 25, 55"
                >

            <Border.BorderBrush>

                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="#FFBB8B8B"/>
                    <GradientStop Color="#FFB67272" Offset="1"/>
                </LinearGradientBrush>

            </Border.BorderBrush>
            <StackPanel Orientation="Vertical" Margin="20,25,20,25">


                <Grid >
                    <TextBox Name="EmailTextBox" Style="{StaticResource LoginTextBoxStyle}" Text="{Binding RegEmailEntered, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}"/>
                    <TextBlock Text="Почта" Tag="{Binding ElementName=EmailTextBox}"
               Style="{StaticResource PlaceholderStyle}" />
                </Grid>



                <Border BorderThickness="0.5">
                    <Border.BorderBrush>
                        <SolidColorBrush Color="#FF367E40" Opacity="0.8"/>
                    </Border.BorderBrush>
                </Border>

                <DockPanel HorizontalAlignment="Center" Margin="0, 30, 0, 0"  VerticalAlignment="Center">

                    <StackPanel Orientation="Vertical">
                        <Grid >
                            <TextBox MaxLength="4" Width="82" Name="NumberTextBox" Style="{StaticResource LoginTextBoxStyle}" />
                            <TextBlock Text="Код" Tag="{Binding ElementName=NumberTextBox}"
               Style="{StaticResource PlaceholderStyle}"/>
                        </Grid>
                        <Border BorderThickness="0.5">
                            <Border.BorderBrush>
                                <SolidColorBrush Color="#FF367E40"  Opacity="0.8"/>
                            </Border.BorderBrush>
                        </Border>
                    </StackPanel>


                    <Button  Margin="80, 3, 0, 3"  Content="Подтвердить" FontSize="20" Style="{StaticResource ButtonMouseRLStyle}" Width="130" Cursor="Hand" Command="{Binding SendEmailCommand}" CommandParameter="{Binding RegEmailContainer, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}" />

                </DockPanel>



                <Grid Margin="0,30,0,0">
                    <TextBox  Name="LoginTextBox" Style="{StaticResource LoginTextBoxStyle}" />
                    <TextBlock Text="Логин" Tag="{Binding ElementName=LoginTextBox}"
               Style="{StaticResource PlaceholderStyle}"/>
                </Grid>

                <Border BorderThickness="0.5">
                    <Border.BorderBrush>
                        <SolidColorBrush Color="#FF367E40"  Opacity="0.8"/>
                    </Border.BorderBrush>
                </Border>

                <Grid Margin="0,30,0,0">
                    <TextBox  Name="PasswordTextBox" Style="{StaticResource LoginTextBoxStyle}" />
                    <TextBlock Text="Пароль" Tag="{Binding ElementName=PasswordTextBox}"
               Style="{StaticResource PlaceholderStyle}"/>
                </Grid>


                <Border BorderThickness="0.5">
                    <Border.BorderBrush>
                        <SolidColorBrush Color="#FF367E40" Opacity="0.8"/>
                    </Border.BorderBrush>
                </Border>








                <Button  Margin="50, 30, 50, 0" Content="Зарегистрироваться"  FontSize="20"  Style="{StaticResource ButtonMouseRLStyle}"  Cursor="Hand" Height="35">


                </Button>



               





            </StackPanel>
        </Border>
    </Grid>
</UserControl>

Сама команда

 public class SendEmailCommand : CommandBase

    {

        public override bool CanExecute(object parameter)
        {
            
            if (parameter.ToString() == "1")
            {
                return false;
            }
            return true;

        }
        

        public override void Execute(object parameter)
        {
            EmailContainer emailContainer = (EmailContainer)parameter;

            EmailServices.SendCode(emailContainer.Email, emailContainer.Code);
            
        }
    }

Выдает исключение, что парамент равен null. Это проблема в коде или так в принципе нельзя делать?


Ответы (1 шт):

Автор решения: aepot

Не занимайтесь переопределением поведения команды, используйте LambdaCommand. Так как я не вижу вашей реализации LambdaCommand, я вам покажу свою.

public class RelayCommand : ICommand
{
    private readonly Action<object> _execute;
    private readonly Predicate<object> _canExecute;

    public event EventHandler CanExecuteChanged
    {
        add => CommandManager.RequerySuggested += value;
        remove => CommandManager.RequerySuggested -= value;
    }

    public RelayCommand(Action<object> execute, Predicate<object> canExecute = null)
        => (_execute, _canExecute) = (execute, canExecute);

    public bool CanExecute(object parameter)
        => _canExecute == null || _canExecute(parameter);

    public void Execute(object parameter)
        => _execute(parameter);
}

Далее получается вот такой конструктор

public RegLeftViewModel()
{
    SendEmailCommand = new RelayCommand(parameter =>
    {
        EmailContainer emailContainer = (EmailContainer)parameter;
        EmailServices.SendCode(emailContainer.Email, emailContainer.Code);
    }, parameter => parameter is EmailContainer); // не совсем понятно, что вы здесь хотели проверить

    RegCommand = new RelayCommand(parameter => 
    {
        DB.Reg(RegLoginEntered, RegPasswordEntered, RegEmailEntered);
    }, parameter => !DB.IfLoginCreated(RegLoginEntered));
}

Подозреваю, что ваша LambdaCommand делает то же самое. Вот и всё лямбдами решается очень просто без добавления лишних методов и классов.

Еще вот это CommandParameter="{Binding RegEmailContainer, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}" должно выглядеть так CommandParameter="{Binding RegEmailContainer}", откуда вы вообще взяли, что UpdateSourceTrigger здесь имеет какой-либо смысл? Привязка к get-only свойству, а вы описываете правила его перезаписи.

→ Ссылка