I am continuing my exploration of WPF and trying to follow MVVM with Commands. My simple code is as follow.
MainWindow.xaml
<Window x:Class="ClickCommand.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ClickCommand"
xmlns:vm="clr-namespace:ClickCommand.ViewModel"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<vm:ButtonViewModel x:Key="ViewModel"/>
</Window.Resources>
<Grid>
<StackPanel Width="350" HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Vertical">
<Button Height="80" FontSize="32" Background="LightBlue" Content="Click Me"
Command="{Binding ButtonCommand, Source={StaticResource ViewModel}}"/>
<TextBox x:Name="textBoxTest" Margin="5" FontSize="36"/>
<Button Height="80" FontSize="32" Background="LightBlue" Content="Click if TextBox as Text"
Command="{Binding ButtonParameterCommand, Source={StaticResource ViewModel}}" CommandParameter="{Binding Text, ElementName=textBoxTest}"/>
</StackPanel>
</Grid>
</Window>
ButtonViewModel.cs
public ButtonViewModel()
{
ButtonCommand = new ButtonCommand();
ButtonParameterCommand = new ButtonParameterCommand();
}
public ICommand ButtonCommand { get; }
public ICommand ButtonParameterCommand { get; }
CommandBase.cs
abstract class CommandBase : ICommand
{
public event EventHandler CanExecuteChanged;
public virtual bool CanExecute(object parameter)
{
return true;
}
public abstract void Execute(object parameter);
protected void OnCanExecutedChanged()
{
CanExecuteChanged?.Invoke(this, new EventArgs());
}
}
ButtonCommand.cs
public override void Execute(object parameter)
{
MessageBox.Show("Button is Clicked");
}
ButtonParameterCommand.cs
public override bool CanExecute(object parameter)
{
return true;
}
public override void Execute(object parameter)
{
MessageBox.Show(parameter as string);
}
My issue is I would like to disable the second button if the textbox above IsNullOrEmpty however the code I thought would address this leaves the button permanently disabled. The code I have been trying is `
public override bool CanExecute(object parameter)
{
if (parameter != null)
{
if (String.IsNullOrEmpty(parameter as string))
{
return false;
}
else
{
return true;
}
}
return false;
}
Is my error in this or the Xaml Binding? I hope someone can help and thank you in advance for your assistance.`
CodePudding user response:
You need to raise the CanExecuteChanged
event of the command whenever the text in the TextBox
changes.
Make the OnCanExecutedChanged()
method of the CommandBase
class public
and call it from the setter of a source property that you bind the TextBox
to:
public class ButtonViewModel
{
public ButtonViewModel()
{
ButtonCommand = new ButtonCommand();
ButtonParameterCommand = new ButtonParameterCommand();
}
private string _text;
public string Text
{
get { return _text; }
set
{
_text = value;
ButtonParameterCommand.OnCanExecutedChanged();
}
}
public ICommand ButtonCommand { get; }
public CommandBase ButtonParameterCommand { get; }
}
XAML:
<TextBox x:Name="textBoxTest" Margin="5" FontSize="36"
Text="{Binding Text, Source={StaticResource ViewModel}}"/>
But you should really look in to how to implement a "relay" or "delegate" command that accepts an Action<object>
and a Predicate<object>
and invoke these in the implementations of the Execute
and CanExecute
methods respectively.