I'm trying to accomplish a correct MVVM architecture in WPF.
I have a player, in the "Model" section there is a Boolean property that says if we are "playing" right now.
public bool IsPlaying
{
get
{
return isPlaying;
}
set
{
isPlaying = value;
OnPropertyChanged("IsPlaying");
}
}
(Notice I implemented the "INotifyPropertyChanged" interface, so the OnPropertyChanged
function reports the change)
in my ViewModel, I have a ImageSource property called "ToggleButtonIcon":
public ImageSource ToggleButtonIcon
{
get
{
if (Model.IsPlaying)
return pauseIcon;
else
return playIcon;
}
}
Which I bind to a "TogglePlayButton" in the view:
<cc:IconButton x:Name="TogglePlayButton"
Style="{StaticResource playButton}"
ImageSource="{Binding Path=ToggleButtonIcon,
UpdateSourceTrigger=PropertyChanged}"
Command="{Binding Path=TogglePlayCommand}"/>
(It's a custom control, but it's working, I checked) Of course I want the button to change its image icon according to if it is playing (pause) and if it is not playing (play).
Problem is the ToggleButtonIcon
does not notify when it changes, and I can't implement the INotifyValueChanged
in the ViewModel section because a. I understood that's not a part of the MVVM architexture, and b. I don't know when it changes since it depends on the IsPlaying
property of Model.
I thought about putting the ToggleButtonIcon
property on the Model section, but that's not "Business Logic" so I don't think that's the right way.
I also thought about using a converter and bind the IconButton
directly to "IsPlaying", which would probably work, but I read here: How can WPF Converters be used in an MVVM pattern? that you should not use converters at all in MVVM because you can do any convertion you want in the "ViewModel" Section.
What's the best way to accomplish this in MVVM architecture?
To me, IsPlaying
should be in the ViewModel, with change notification implemented, as it represents an application state of sorts.
To solve the issue I would recommend taking the ToggleButtonIcon
out of the ViewModel, and creating a DataTrigger
on the IconButton
control (via its Style
), that binds to the IsPlaying
property (on the ViewModel) and alters the ImageSource
property based on that.
The model of MVVM should only hold class entities and those entities can on occasion have an INotiftPropertyChanged
, but generally they do not.
What your intent though is that it is to convey a status and that should be on your viewmodel.
I would recommend that you have the status of IsPlaying
be on the View Model (VM) and bind to that. Then in the command of TogglePlayCommand
, it will set that property on the VM.
That way both items update propertly on a change to either. You can still new up your original object in the model and on the Setter
of the VM's IsPlaying
set the class instance property to its value if needed .
Take a look at my blog post Xaml: ViewModel Main Page Instantiation and Loading Strategy for Easier Binding . Take note on how I use OnPropertyChanged
to push change messages on other operations which can all for the flexibility you seek as well as having the viewmodel hold statuses and not the models.
You should put bool on class which implements interface INotifyPropertyChange: Here an example:
public class Game : INotifyPropertyChanged
{
private bool _isPlaying;
public string IsPlaying
{
get { return _isPlaying; }
set {
_isPlaying = value;
this.NotifyPropertyChangedBool();
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChangedBool()
{
if (PropertyChanged != null)
{
PropertyChanged(this, new
PropertyChangedEventArgs("IsPlaying"));
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.