2

I have a search dialog where I want to disable the search button during the search. This is the current code but the button does not get deactivated

View:

<Button Content="Search" Command="{Binding StartSearchCommand}" IsEnabled="{Binding IsNotSearching}" /> 

ViewModel:

private bool _isNotSearching; public bool IsNotSearching { get { return _isNotSearching; } set { _isNotSearching = value; OnPropertyChanged("IsNotSearching"); } } private RelayCommand<object> _startSearchCommand; public ICommand StartSearchCommand { get { if (_startSearchCommand == null) _startSearchCommand = new RelayCommand<object>(p => ExecuteSearch()); return _startSearchCommand; } } private void ExecuteSearch() { IsNotSearching = false; //do some searching here IsNotSearching = true; } 
9
  • 1
    That's because you block UI thread by perfoming Thread.Sleep. If you would perform some task in background thread everything should work as you expect Commented Sep 9, 2015 at 13:28
  • Tried it. Gave it something to do. But the button looks clicked in the time of execution and not deactivated Commented Sep 9, 2015 at 13:35
  • It is happening but so fast you don't see it. ExecuteSearch() does not update the UI until it is done so IsNotSearching = false and IsNotSearching = true happend at the same time. Commented Sep 9, 2015 at 13:52
  • @Frisbee: I calculate something that takes very long. I can see it is clicked unitl it finishes Commented Sep 9, 2015 at 14:08
  • @juergend So you can see it clicked. What does that prove? Commented Sep 9, 2015 at 14:12

4 Answers 4

9
+50

I've made an AsyncDelegateCommand for that reason (based on famous DelegateCommand), it internally disable command (in UI) during executing command action:

public class AsyncDelegateCommand : ICommand { readonly Action<object> _execute; readonly Predicate<object> _canExecute; bool _running; public event EventHandler CanExecuteChanged; public AsyncDelegateCommand(Action<object> execute, Predicate<object> canExecute = null) { _execute = execute; _canExecute = canExecute; } public bool CanExecute(object parameter) { return (_canExecute == null ? true : _canExecute(parameter)) && !_running; } public async void Execute(object parameter) { _running = true; Update(); await Task.Run(() => _execute(parameter)); _running = false; Update(); } public void Update() { if (CanExecuteChanged != null) CanExecuteChanged(this, EventArgs.Empty); } } 

xaml:

<Button Command="{Binding SomeCommand}" .../> 

ViewModel:

AsyncDelegateCommand SomeCommand { get; } // in constructor SomeCommand = new AsyncDelegateCommand(o => { Thread.Sleep(5000); }); // code to run 
Sign up to request clarification or add additional context in comments.

Comments

1

I am not sure about looks when it was clicked and disabled - it is possible that it looks same.

But netaholic is right. If you execute logic in main UI thread it is possible that UI is frozen till your execution end (and isn't changed or changed to fast).

Try to put your logic in dispatcher. Like in next part of the code.

Application.Current.Dispatcher.BeginInvoke( DispatcherPriority.Background, new Action(() => { //do some searching here })); 

BTW, I took this code there.

EDIT: don't use this for your solution. This is wrong (check comments).

Use dispatcher when you need to update visual element async.

Application.Current.Dispatcher.BeginInvoke( DispatcherPriority.Background, new Action(() => { textbox.Content = "some result"; })); 

1 Comment

Application Dispatcher executes the delegates on UI Thread. This will freeze the application as well.
0

You could try command can execute to disable the command without adding IsEnabled property

private RelayCommand _startSearchCommand; public RelayCommand StartSearchCommand { get { return _startSearchCommand?? (_startSearchCommand= //Added can execute command , only execute if system is not busy at the moment. new RelayCommand(async () => await OnExecuteSearch(), () => !IsBusy)); } } 

Command handler

internal async Task OnExecuteSearch() { IsBusy = true; //Execute your action //and finally IsBusy = false; } 

Xaml

 <Button Command="{Binding StartSearchCommand}"> 

The canexecute in the Relay Command will control the IsEnabled property for you.

Comments

0

This code must work.

private async void ExecuteSearch() { IsNotSearching = false; var task = Task.Factory.StartNew(() => { //do some searching here }); await task; IsNotSearching = true; } 

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.