Comments (7)
@brminnick thank you very much for your help with code and explanation! :)
I really appreciate it!)
from asyncawaitbestpractices.
Hi @tyrgin!
Can you provide a reproduction sample where CanExecuteChanged
does not fire?
It does not automatically fire when the value of canExecute
changes; you must call RaiseCanExecuteChanged
after changing the value canExecute
to fire CanExecuteChanged
.
Here is a sample from my Unit Tests demonstrating it:
from asyncawaitbestpractices.
Hi @brminnick
Thank you for your answer!
Basically what I have is:
public class ViewModelCalculate : INotifyPropertyChanged
{
private bool isBusy;
private ObservableCollection<BusSection> busSections;
public ViewModelCalculate(ObservableCollection<BusSection> busSections)
{
this.busSections = busSections;
}
#region Command
private IAsyncCommand calculateAsync;
public IAsyncCommand CalculateAsyncCommand => calculateAsync ??
new AsyncCommand(ExecuteCalculateAsync, CanExecuteCalculate);
private async Task ExecuteCalculateAsync( ) { ... }
private bool CanExecuteCalculate( ) => busSections.Count() > 0 && !IsBusy;
#endregion
#region INotifyPropertyChanged
public bool IsBusy { get => isBusy; set { isBusy = value; OnPropertyChanged("IsBusy"); } }
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string prop = "")
{ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop)); }
#endregion
}
And in other ViewModel I update the busSections
collection.
As I said I tried to subscribe CalculateAsync.RaiseCanExecuteChanged()
on busSections.CollectionChanged
in ViewModelCalculate ctor
, but that also gave nothing - RaiseCanExecuteChanged()
executed but it the event CanExecuteChanged
was always null in this part
public void RaiseCanExecuteChanged()
{
CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
Where I should call RaiseCanExecuteChanged()
?
Actually I've found other hacky way:
///the VM where i update BusSections collection
public class OtherViewModel
{
private ObservableCollection<BusSection> busSections;
public ObservableCollection<BusSection> BusSections { get=>busSections; set { busSections =
value; OnPropertyChanged(); }}
public ViewModelCalculate VmCalculate {get;set;}
void UpdateBusSection ()
{
///add item to BusSections
///with next line works good
OnPropertyChanged("VmCalculate");
}
}
Sorry for messy explanation, i've tried a few options, eventually came to OnPropertyChanged("VmCalculate")
without calling RaiseCanExecuteChanged()
, but i believe there is should be right way.
from asyncawaitbestpractices.
@brminnick it has occurred to me today that I RaiseCanExecuteChanged always for a new instance of Command...
so I changed
public ViewModelCalculate(ObservableCollection<BusSection> busSections)
{
busSections.CollectionChanged += (sender,e)=> RaiseChange();
}
private IAsyncCommand<string> calculateAsync;
public IAsyncCommand<string> CalculateAsyncCommand => calculateAsync ??
new AsyncCommand(x=>ExecuteCalculateAsync(x), x=>CanExecuteCalculate(x));
to this
private bool busSectionAny;
private IAsyncCommand<string> calculateAsync;
public ViewModelCalculate(ObservableCollection<BusSection> busSections)
{
busSections.CollectionChanged += (sender,e)=> RaiseChange();
}
void RaiseChange()
{
if(busSections.Any() ^ busSectionAny)
{
busSectionAny = busSectionAny?false:true;
((AsyncCommand<string>)CalculateAsyncCommand).RaiseCanExecuteChanged();
}
}
public IAsyncCommand<string> CalculateAsyncCommand
{
get
{
calculateAsync ??= new AsyncCommand<string>(x => ExecuteCalculateAsync(x), x => CanExecuteCalculate(x));
return calculateAsync;
}
}
And now it works without hacky OnPropertyChanged :)
Is this resolve ok? Or I should change something?
from asyncawaitbestpractices.
How do you think, is it ok to invoke RaiseCanExecuteChanged
from different ViewModel
?
from asyncawaitbestpractices.
For your example, you need to call CalculateAsyncCommand.RaiseCanExecuteChanged()
every time the value of bool CanExecuteCalculate()
changes.
Because bool CanExecuteCalculate()
references both busSections.Count()
and IsBusy
, you need to call CalculateAsyncCommand.RaiseCanExecuteChanged()
every time the value of busSections.Count()
and IsBusy
changes.
I also fixed a bug with your initialization of CalculateAsyncCommand
, and I changed OnPropertyChanged("IsBusy")
to OnPropertyChanged()
.
When calling OnPropertyChanged()
, you don't need to pass in the property name because OnPropertyChanged
uses [CallerMemberName]
which will automatically pass in "IsBusy"
because IsBusy
is the "CallerMemberName", ie the name of the Property calling OnPropertyChanged
is "IsBusy" and thus the value of string prop
will automatically be "IsBusy".
Here's the updated code:
public class ViewModelCalculate : INotifyPropertyChanged
{
private bool isBusy;
private IAsyncCommand calculateAsync;
private ObservableCollection<BusSection> busSections;
public ViewModelCalculate(ObservableCollection<BusSection> busSections)
{
this.busSections = busSections;
}
public event PropertyChangedEventHandler PropertyChanged;
public IAsyncCommand CalculateAsyncCommand => calculateAsync ??
(calculateAsync = new AsyncCommand(ExecuteCalculateAsync, CanExecuteCalculate));
public bool IsBusy
{
get => isBusy;
set
{
isBusy = value;
OnPropertyChanged();
CalculateAsyncCommand.RaiseCanExecuteChanged();
}
}
private async Task ExecuteCalculateAsync( )
{
// Whenever you modify `busSections`, call `CalculateAsyncCommand.RaiseCanExecuteChanged()`
// Here's an example:
// busSections.Clear();
// CalculateAsyncCommand.RaiseCanExecuteChanged();
// Here's another example:
// busSections.Add(new BusStation());
// CalculateAsyncCommand.RaiseCanExecuteChanged();
}
private bool CanExecuteCalculate( ) => busSections.Count() > 0 && !IsBusy;
public void OnPropertyChanged([CallerMemberName] string prop = "") =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop));
}
from asyncawaitbestpractices.
And thanks so much for the feedback!
I've updated the docs to include an example of CanExecuteChanged
:
from asyncawaitbestpractices.
Related Issues (20)
- What Dotnet native directives to use with .Net Native tool chain?
- Windows 11 - Smart App Control HOT 2
- CanExecute is called only once HOT 2
- Async / Await != Multithread HOT 2
- Add SourceLink
- CanExecute issue HOT 2
- Error when running from signed assembly HOT 5
- Is "Sealed" necessary for AsyncCommand? HOT 2
- Execute parameter ignored HOT 3
- WinRT: Windows 8.1 SafeFireAndForget issue "No overload for method" HOT 12
- Question about capctured context in AsyncCommand HOT 1
- ArgumentException with Dynamic Handlers HOT 2
- Possible improvement for explicit ICommand.Execute() implementation in AsyncCommand? HOT 1
- Why's MVVMLight's message sent in vain? HOT 13
- Question: Cancellation HOT 1
- SafeFireAndForget is not safe HOT 8
- Add NuGet README
- Does RaiseCanExecuteChanged need to be called on the UI thread?
- Parameter change does not invoke CanExecuteChanged HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from asyncawaitbestpractices.