C# – WPF View sets ViewModel properties to null on closing

cmvvmnetwpf

I have an application where I'm displaying UserControls in a GroupBox. To display the controls, I'm binding to a property in the ViewModel of the main form, which returns a ViewModel to be displayed. I've got DataTemplates set up so that the form automatically knows which UserControl/View to use to display each ViewModel.

When I display a different UserControl, I keep the ViewModel of the previous control active, but the Views are discarded automatically by WPF.

The problem that I'm having is that when the view shuts down, any two way bindings to the properties in the ViewModel are immediately set to null, and so when I display the ViewModel again all of the values are just set to null in the UI.

I assume this is because as part of the View closing down it disposes and clears any values in the controls it contains, and since the bindings are in place they propagate down to the ViewModel as well.

DataTemplates in my resources

<DataTemplate DataType="{x:Type vm:HomeViewModel}">
    <vw:HomeView />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:SettingsViewModel}">
    <vw:SettingsView />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:JobListViewModel}">
    <vw:JobListView />
</DataTemplate>

Code used to display user controls

<GroupBox>
    <ContentControl  Content="{Binding Path=RightPanel}" />
</GroupBox>

Example of a control that I'm binding in one of the Views:

    <ComboBox Name="SupervisorDropDown" ItemsSource="{Binding Path=Supervisors}" DisplayMemberPath="sgSupervisor" 
           SelectedValuePath="idSupervisor" SelectedValue="{Binding Path=SelectedSupervisorID}" />

and the relevant ViewModel properties:

public ObservableCollection<SupervisorsEntity> Supervisors
    {
        get
        {
            return supervisors;
        }
    }

public int? SelectedSupervisorID
{
    get
    {
        return selectedSupervisorID;
    }
    set
    {
        selectedSupervisorID = value;
        this.OnPropertyChanged("SelectedSupervisorID");
    }
}

Any idea on how to stop my Views nulling the values in my ViewModels? I'm thinking that maybe I need to set the DataContext of the View to null before it closes down, but I'm not sure how to go about that with the way things are currently binding.

Best Answer

I've found one possible solution, but I really don't like it.

It turns out the DataContext IS being set to null already, but that doesn't help. It happens before the property is set to null. What appears to be happening is that the data bindings aren't being removed before the UserControl/View disposes of itself, and so the null value propagates down when the control is removed.

So when the DataContext changes, if the new context is null then I remove the relevant bindings on the ComboBox, as follows:

private void UserControl_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    if (e.NewValue == null)
    {
        SupervisorDropDown.ClearValue(ComboBox.SelectedValueProperty);
    }
}

I'm not a big fan of this method, because it means I have to do remember to do it for every databound control I use. If there was a way I could just have every UserControl just remove their bindings automatically when they close that would be ok, but I can't think of any way to do that.

Another option might be to just restructure my app, so that the Views don't get destroyed until the ViewModels do - this would sidestep the problem entirely.

Related Topic