Использование команд в WPF
Как правильно создать Command, чтобы при нажатии на кнопку, текст улетал в TextBlock из TextBox. Пробовал, но не получалось. Решил понизить сложность и просто вывести MessageBox, но опять ничего
MainWindow.xaml:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Vertical">
<TextBox Text="{Binding Path=SynchronizedText, UpdateSourceTrigger=PropertyChanged, Mode=OneWayToSource}" Height="30" BorderBrush="Blue">
<TextBox.Resources>
<Style TargetType="Border">
<Setter Property="CornerRadius" Value="10"/>
</Style>
</TextBox.Resources>
</TextBox>
<Border BorderBrush="Black" BorderThickness="1" Width="130" Height="30" CornerRadius="10" Margin="0,10,0,0">
<TextBlock Text="{Binding Path=SynchronizedText, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</StackPanel>
<StackPanel Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Vertical">
<TextBox Text="" Height="30" BorderBrush="Blue">
<TextBox.Resources>
<Style TargetType="Border">
<Setter Property="CornerRadius" Value="10"/>
</Style>
</TextBox.Resources>
</TextBox>
<Border BorderBrush="Black" BorderThickness="1" Width="130" Height="30" CornerRadius="10" Margin="0,10,0,0">
<TextBlock Text="" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<Button Content="ПЕРЕСЛАТЬ" Width="130" Height="30" Margin="0,10" Command="{Binding command}"/>
</StackPanel>
</Grid>
MainWindow.xaml.cs:
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainWindowVM();
}
BaseVM.cs:
class BaseVM : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
MainWindowVM.cs:
class MainWindowVM : BaseVM
{
private string _synchronizedText;
public string SynchronizedText
{
get => _synchronizedText;
set
{
_synchronizedText = value;
OnPropertyChanged(nameof(SynchronizedText));
}
}
public ICommand command { get; set; }
public MainWindowVM()
{
command = new Command();
}
private bool canExecuteMethod(object parameter)
{
return true;
}
private void ExecuteMethod(object parameter)
{
MessageBox.Show("OK","OK",MessageBoxButton.OK, MessageBoxImage.Information);
}
}
Command.cs:
class Command : ICommand
{
public event EventHandler CanExecuteChanged;
Action<object> executeMethod;
Func<object, bool> canExecuteMethod;
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
executeMethod(parameter);
}
}
Ответы (1 шт):
Например вот такая реализация команды:
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 ICommand MyCommand { get; } = new RelayCommand(parameter =>
{
MessageBox.Show(SynchronizedText);
},
parameter => SynchronizedText?.Length > 0); // CanExecute, заблокирует кнопку, если условие не выполнено
<Button ... Command="{Binding MyCommand}"/>
parameter служит для передачи параметра в команду, например так:
public ICommand MyCommand { get; } = new RelayCommand(parameter =>
{
string text = (string)parameter;
MessageBox.Show(text);
},
parameter => parameter is string text && text.Length > 0);
<Button ... Command="{Binding MyCommand}" CommandParameter="{Binding SynchronizedText}"/>
Сам CanExecute в этой реализации команды необязателен, поэтому можно просто вот так:
public ICommand MyCommand { get; } = new RelayCommand(parameter =>
{
MessageBox.Show(SynchronizedText);
});
Это будет значить, что CanExecute всегда true.
Немного подробней про CanExecute. Представьте что кнопка выполняет примерно такой код, просто для понимания:
var parameter = ...;
if (Command.CanExecute(parameter))
{
Command.Execute(parameter);
}
То есть если метод CanExecute вернул false, сама команда гарантированно не будет вызвана.
А так же кнопка подписывается на событие Command.CanExecuteChanged и при сработке события проверяет CanExecute и меняет свой IsEnabled в зависимости от полученного оттуда значения. Поэтому если используете команду, управляйте IsEnabled только из кода команды через условие CanExecute.
Если взглянуть в RelayCommand, то можно увидеть, что событие CanExecuteChanged сделано как прокси-событие для CommandManager.RequerySuggested, а это событие вызывается при любом событии ввода - тык мышкой или при вводе с клавиатуры.
Но бывают ситуации, когда надо принудительно вызвать CanExecute, не дожидаясь ввода, чтобы улучшить поведение интерфейса. Для этого просто выполните в коде:
CommandManager.InvalidateRequerySuggested();

