-3

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:

  1. Display items (installations) from model in ListView (currently: works)
  2. Filter/Show only installations that meet some criteria (currentrly: works)
  3. Reflect changes in 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!

simon
  • 1,161
  • 10
  • 27

1 Answers1

0

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.

simon
  • 1,161
  • 10
  • 27