Search code examples
c#wpfmvvmentity-framework-6mvw

How to disable ListView selection change when item has changes in MVVM/MVW?


I have simple viewmodel:

private List<Item> itemsList;
public List<Item> ItemsList
{
    get { return itemsList; }
    set
    {
        itemsList= value;
        NotifyPropertyChanged();
    }
}

private Item selectedItem;
public Item SelectedItem
{
    get { return selectedItem; }
    set
    {
        selectedItem = value;
        NotifyPropertyChanged();
    }
}

// I call this method from button handler 
// window code behind: vm.SaveChanges()
// instead of RelayCommand because I'm lazy (I don't need strict MVVM)
public void SaveChanges() 
{
    context.SaveChanges();
}

Im my view I have a ListView:

<ListView 
    ItemsSource="{Binding ItemsList}" 
    SelectedItem="{Binding SelectedItem}" 
/>

and few controls with Item properties:

<TextBox Text="{Binding SelectedItem.Name}"/>
<TextBox Text="{Binding SelectedItem.Phone}"/>

When I select an Item on a ListView - SelectedItem field values appear in TextBoxes, I can edit them and save them. Everything works fine, but I don't want to allow user to change selected item before he saves changes, because user will not see what was changed in another item(s).

Now I want to disable selection change on ListView, when item has unsaved changes.

I was experimenting with ViewModel property like this:

public bool NoUnsavedChanges
{
    get { return !context.ChangeTracker.HasChanges(); }
    private set;
}

and binding it to IsEnabled property of ListView, but of course it does not work because there is no NotifyPropertyChanged() for this property.

My question is: how can I disable ListView selection change (or disable it totally) when selected item (or if there are unsaved changes in the entire context)?


Solution

  • ...and binding it to IsEnabled property of ListView, but of course it does not work because there is no NotifyPropertyChanged() for this property.

    Raise a PropertyChanged event then. Your view model should implement the INotifyPropertyChanged event and so should your Item class. If it doesn't you should replace it with a wrapper class that does. You could then raise the PropertyChanged event for the NoUnsavedChanges property of the view model whenever the state of the SelectedItem changes, e.g.:

    private List<Item> itemsList;
    public List<Item> ItemsList
    {
        get { return itemsList; }
        set
        {
            itemsList = value;
            NotifyPropertyChanged();
        }
    }
    
    private Item selectedItem;
    public Item SelectedItem
    {
        get { return selectedItem; }
        set
        {
            if (selectedItem != null)
                selectedIten.PropertyChanged -= OnItemPropertyChanged;
    
            selectedItem = value;
            NotifyPropertyChanged();
    
            if (selectedItem != null)
                selectedIten.PropertyChanged += OnItemPropertyChanged;
        }
    }
    
    private void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        NotifyPropertyChanged("NoUnsavedChanges");
    }
    
    public bool NoUnsavedChanges
    {
        get { return !context.ChangeTracker.HasChanges(); }
    }
    
    public void SaveChanges()
    {
        context.SaveChanges();
        NotifyPropertyChanged("NoUnsavedChanges");
    }