0

Brand new to WPF and MVVM. My application has a button to browse for a file and a start button to perform a task with the selected file. I only want the start button available to the user if they have selected a file using the browse button. I am using the file path property in the ViewModel as the CommandParameter but this does not work. Any help appreciated.

XAML

<Button Grid.Column="1" Grid.Row="2" Content="Browse File" Margin="0,0,5,5" Command="{Binding Path=CommandBrowseFile}" ></Button> <Button Grid.Column="1" Grid.Row="3" Grid.ColumnSpan="2" Content="Start" Margin="0,0,0,5" Command="{Binding Path=CommandStart}" CommandParameter="{Binding Path=FilePath}"></Button> 

ViewModel

public class MyViewModel : ViewModelBase { public RelayCommand CommandBrowseFile { get; private set; } public RelayCommand CommandStart { get; private set; } private string _filePath; public MyViewModel() { //L5XPath = "test"; CommandBrowseFile = new RelayCommand(BrowseFile); CommandStart = new RelayCommand(Start, CanStart); } public string FilePath { get { return _filePath; } set { _filePath = value; } } public void BrowseFile(object message) { // Configure open file dialog box OpenFileDialog dlg = new OpenFileDialog(); dlg.FileName = "Document"; // Default file name dlg.DefaultExt = ".l5x"; // Default file extension dlg.Filter = "l5x files (.l5x)|*.l5x"; // Filter files by extension // Show open file dialog box Nullable<bool> result = dlg.ShowDialog(); // Process open file dialog box results FilePath = result == true ? dlg.FileName : null; } public void Start(object message) { //Do something } public bool CanStart(object message) { return message != null ? true : false; } } 

RelayCommand

public class RelayCommand : ICommand { readonly Action<object> _execute; readonly Predicate<object> _canExecute; public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } public RelayCommand(Action<object> execute, Predicate<object> canExecute) { if (execute == null) { throw new NullReferenceException("execute"); } else { _execute = execute; _canExecute = canExecute; } } //public void RaiseCanExecuteChanged() //{ // if (CanExecuteChanged != null) // CanExecuteChanged(this, new EventArgs()); //} public RelayCommand(Action<object> execute) : this(execute, null) { } public bool CanExecute(object parameter) { return _canExecute == null ? true : _canExecute(parameter); } public void Execute(object parameter) { _execute.Invoke(parameter); } } 
1
  • You haven't implemented binding correctly. See duplicates. Commented Feb 8, 2021 at 21:33

3 Answers 3

0

I would modify CanStart method and call OnPropertyChanged() in FilePath's setter.

public bool CanStart(object message) { return !string.IsNullOrEmpty(FilePath); } public string FilePath { get { return _filePath; } set { _filePath = value; OnPropertyChanged(); // method in your ViewModelBase CommandStart.RaiseCanExecuteChanged(); } } 

Also uncomment RaiseCanExecuteChanged and call this method on CommandStart command when FilePath is updated to notify UI whether the command is enabled or not.

public event EventHandler CanExecuteChanged; public void RaiseCanExecuteChanged() { if (CanExecuteChanged != null) CanExecuteChanged(this, new EventArgs()); } 
Sign up to request clarification or add additional context in comments.

4 Comments

Why does my command parameter for the start button always have a null value even when the binding property is not null?
@James Trying to reproduce and it's working fine. Do you see any binding errors in output window?
There is nothing showing in my XAML Binding Failures output
No errors in the XAML Binding Failures window. Your solution works, I was just hoping to understand why mine does not.
0

You have not used CommandStart.RaiseCanExecuteChanged(); And this command invokes the CanStart() function, where you must check the _filePath value to see if it is empty or not

public string FilePath { get { return _filePath; } set { _filePath = value; CommandStart.RaiseCanExecuteChanged(); } } public bool CanStart(object message) { return _filePath != null ? true : false; } 

in RelayCommand

public event EventHandler CanExecuteChanged; public void RaiseCanExecuteChanged() { if (CanExecuteChanged != null) CanExecuteChanged(this, EventArgs.Empty); } 

2 Comments

Thanks, your solution works but I was interested in understanding why mine does not.
I did not understand this line CommandManager.RequerySuggested so I used my own code and added a description to the answer
0

You have to call the PropertyChanged event on the property being used within the command parameter.

public string FilePath { get { return _filePath; } set { _filePath = value; NotifyPropertyChanged("FilePath"); } } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.