Search code examples
wpfmvvmdata-bindingbindingviewmodel

ViewModel child doesn't refresh proper? binding in WPF


I have one View that has another one inside. I want to make ViewModel for both of them. But apparently Binding in Child View is not working properly or I have done wrong binding, perhaps.

I have debugged that Child ViewModel is recreated every time I have selected different row in Parent ViewModel. But UI, doesn't refresh, despite UpdateSourceTrigger=PropertyChanged.

If I edit Binding in XAML while running app then it gets refreshed (as Binding probably is regenerated).

I could set UpdateSourceTrigger=Explicit, but I can't call UpdateSource from none of ViewModels.

PARENT VIEW:

<UserControl ... DataContext="{Binding ProjectsViewModel, Source={StaticResource ViewModelLocator}}">
    <Grid>
        <poc:AdvancedListView ItemsSource="{Binding Projects}" SelectedObject="{Binding SelectedProject, Mode=TwoWay}"/>
        ...
        <ScrollViewer>
            <StackPanel Orientation="Vertical">
                ...
                <poc:Section SectionName="ATTACHMENTS">
                    <poc:AttachmentsControl DataContext="{Binding AttachmentsViewModel, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" /> // THIS IS BINDING BETWEEN VM
                </poc:Section>
            </StackPanel>
        </ScrollViewer>
    </Grid>
</UserControl>

PARENT VIEWMODEL:

public class ProjectsViewModel : BaseViewModel
{
    public ProjectsViewModel(ObservableCollection<Project> projects)
    {
        this.Projects = projects;
    }

    public ObservableCollection<Project> Projects { get; }

    private Project selectedProject;
    public Project SelectedProject
    {
        get { return selectedProject; }
        set
        {
            SetPropertyAndNotify(ref selectedProject, value);
            AttachmentsViewModel = new AttachmentsViewModel(selectedProject.Attachments); // THIS IS CREATION OF CHILD VM
        }
    }

    public AttachmentsViewModel AttachmentsViewModel { get; set; }
}

CHILD VIEW:

<UserControl ... x:Name="attachmentControl">
    <Grid x:Name="mainGrid">
        ...
        <ListView x:Name="attachmentsListView" ItemsSource="{Binding Attachments, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" SelectionMode="Single"> // THIS IS BINDING TO LIST THAT IS NOT WORKING
            <ListView.View>
                <GridView>
                    ...
                </GridView>
            </ListView.View>
        </ListView>
    </Grid>
</UserControl>

CHILD VIEWMODEL:

public class AttachmentsViewModel : BaseViewModel
{
    public ObservableCollection<Attachment> Attachments { get; set; }

    public AttachmentsViewModel(ObservableCollection<Attachment> attachments)
    {
        Attachments = attachments;
    }

}

What I do wrong or what concept I have understood wrong?


Solution

  • public class ProjectsViewModel : BaseViewModel
    {
        public ProjectsViewModel(ObservableCollection<Project> projects)
        {
            this.Projects = projects;
        }
    
        public ObservableCollection<Project> Projects { get; }
    
        private Project selectedProject;
        public Project SelectedProject
        {
            get { return selectedProject; }
            set
            {
                SetPropertyAndNotify(ref selectedProject, value);
    
                // THIS IS CREATION OF CHILD VM
                AttachmentsViewModel = new AttachmentsViewModel(selectedProject.Attachments);         
            }
        }
    
        private AttachmentsViewModel _attachmentsViewModel;
        public AttachmentsViewModel AttachmentsViewModel
        {
           get => _attachmentsViewModel;
           set => SetPropertyAndNotify(_attachmentsViewModel, value);
        }
    }
    
    public class AttachmentsViewModel : BaseViewModel
    {
        // This should be a Read Only property
        public ObservableCollection<Attachment> Attachments { get; /* set; */}
    
        public AttachmentsViewModel(ObservableCollection<Attachment> attachments)
        {
            Attachments = attachments;
        }
    }
    

    Additional recommendation: Adding extra logic to the property setter - is bad. Surely in the BaseViewModel implementation there is an opportunity to set the dependence of properties on each other in a different way.