I am learning MVVM pattern while refactoring an app to MVVM.
I have a model class Machine
that provides a list of installations in a form of ObservableCollection<Installation> Installations
.
In one of the windows (views) I need to display only those installations that have updates (thus meet the following criteria):
private void InstallationsToUpdateFilter(object sender, FilterEventArgs e)
{
var x = (Installation)e.Item;
bool hasNewVersion = ShowAllEnabledInstallations ? true : x.NewVersion != null;
bool isSetAndOn = !String.IsNullOrEmpty(x.Path) && x.CheckForUpdatesFlag;
e.Accepted = isSetAndOn && hasNewVersion;
}
private void OnFilterChanged()
{
installationsToUpdateSource?.View?.Refresh();
}
I am doing this by filtering in my ViewModel:
class NewVersionViewModel : ViewModelBase
{
private Machine machine = App.Machine;
...
public NewVersionViewModel(...)
{
...
InstallationsToUpdate.CollectionChanged += (s, e) =>
{
OnPropertyChanged("NewVersionsAvailableMessage");
OnFilterChanged();
};
installationsToUpdateSource = new CollectionViewSource();
installationsToUpdateSource.Source = InstallationsToUpdate;
installationsToUpdateSource.Filter += InstallationsToUpdateFilter;
}
public ObservableCollection<Installation> InstallationsToUpdate
{
get { return machine.Installations; }
set { machine.Installations = value; }
}
internal CollectionViewSource installationsToUpdateSource { get; set; }
public ICollectionView InstallationsToUpdateSourceCollection
{
get { return installationsToUpdateSource.View; }
}
...
}
This is done by custom ListView:
<ListView ItemsSource="{Binding InstallationsToUpdateSourceCollection}" ... >
...
<ListView.ItemTemplate>
<DataTemplate>
<Grid ...>
<Grid ...>
<CheckBox Style="{StaticResource LargeCheckBox}"
IsChecked="{Binding Path=MarkedForUpdate, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{Binding Path=HasNewVersion}"
/>
</Grid>
<Label Content="{Binding Path=InstalledVersion.Major}" Grid.Column="1" Grid.Row="0" FontSize="50" FontFamily="Segoe UI Black" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,-10,0,0"/>
...
<Grid.ContextMenu>
<ContextMenu>
...
</ContextMenu>
</Grid.ContextMenu>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
All of this works - until I try to "send" <CheckBox IsChecked="{Binding Path=MarkedForUpdate...
back to my model - so it will be stored there.
How it can be done? (Can I have some kind of setter on ICollectionView
?)
Current architecture can be changed. What I ultimately need:
installations
) from model in ListView
(currently: works
)works
)MarkedForUpdate
checkbox back to model (currently: not working
)I've googled a lot but was unable to find a relevant solution or suggestions. Any help would be greatly appreciated. Thanks!
I figured the problem out. Although it was a silly mistake, I still want to share it to save someone's time.
The model itself updates in the configuration described above. The problem was that what model property ( Machine.Installations
in my case) did not implement INotifyPropertyChanged interface so other Views (through their corresponding ViewModels) were not aware of changes. Thus one should use OnPropertyChanged/RaisePropertyChanged
not only in ViewModel , but in Model as well.
Hope this may help someone.
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.