Search code examples
wpflistviewmvvmlistviewitem

WPF - Refresh ListView bound to ViewModel


I'm writing an application at the minute and have come across an issue with a ListView which displays items from a View Model; there's a property in said view model "Selected" which is just a bool and, I bind this to the ListView's "IsSelected" property.

I have a button to "Clear Selection" which iterates over each item that is selected and sets it to false; this works and the command is updated and the buttons are no longer enabled since there's nothing where Selected == true.

In Pictures

Item is selected; buttons are available.

Item is selected; buttons are available.

Button "Clear Selection" is pressed Clear Selection is pressed

At this point, I can no longer click the control to select the element; I have to control click it to unselect it which puts everything back as disabled and nothing selected.

Here's the XAML for the control - not sure what I could be doing wrong but I'm unable to find an answer thus far.

<ListView ItemsSource="{Binding AssignableItems, UpdateSourceTrigger=PropertyChanged}" Grid.Row="2" SelectionMode="Extended">
    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem" BasedOn="{StaticResource lviStyleBase}">
            <Setter Property="IsSelected" Value="{Binding Selected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
        </Style>
    </ListView.ItemContainerStyle>
    <ListView.View>
        <GridView>
            <GridViewColumn Header="Created" DisplayMemberBinding="{Binding ContactCreated}" Width="Auto" />
            <GridViewColumn Header="Contact Name" DisplayMemberBinding="{Binding ContactName}" Width="Auto" />
            <GridViewColumn Header="Company" DisplayMemberBinding="{Binding Company}" Width="Auto" />
        </GridView>
    </ListView.View>
</ListView>

Here's the ViewModel:

namespace CSI.ViewModels
{
    public class AssignViewModel
        : ModelBase
    {
        #region Properties
        private bool viewingFilters;

        public bool Filtering
        {
            get { return viewingFilters; }
            set { if ( SetValue(ref viewingFilters, value) ) Notify(); }
        }

        private bool assigning;

        public bool Assigning
        {
            get { return assigning; }
            set { if ( SetValue(ref assigning, value) ) Notify(); }
        }

        private string viewTitle = "Assign";
        public string ViewTitle
        {
            get => $"{viewTitle}{(Filtered ? " (filtered)" : "")}";
        }

        private AssignFilterValuesModel filters;

        public AssignFilterValuesModel Filters
        {
            get { return filters; }
            set { SetValue(ref filters, value); }
        }

        public bool Filtered
        {
            get
            {
                if ( filters == null ) return false;

                return assignables.Count() != AssignableItems.Count();
            }
        }

        private bool loading;

        public bool Loading
        {
            get { return loading; }
            set { SetValue(ref loading, value); }
        }

        private ObservableCollection<AssignableWorkItemModel> assignables;
        public ObservableCollection<AssignableWorkItemModel> AssignableItems
        {
            get
            {
                if ( assignables == null ) return null;
                if ( Filters == null ) return assignables;

                var retval = assignables.Where(x => 1 == 1);

                if ( Filters.Dealers.Any(x => x.Selected) )
                    retval = retval.Where(x => filters.Dealers.Where(o => o.Selected).Select(o => o.Key).ToList().Contains(x.Dealer));

                if ( Filters.VehicleModels.Any(x => x.Selected) )
                    retval = retval.Where(x => filters.VehicleModels.Where(o => o.Selected).Select(o => o.Key).ToList().Contains(x.VehicleModel));

                return new ObservableCollection<AssignableWorkItemModel>(retval);
            }
            set => SetValue(ref assignables, value);
        }
        private ObservableCollection<AssignableWorkItemModel> selected;
        public ObservableCollection<AssignableWorkItemModel> SelectedItems
        {
            get => selected;
            set => SetValue(ref selected, value);
        }
        #endregion
        #region Commands
        private RelayCommand displayFilterScreen;
        public void Execute_DisplayFilters(object _)
        {
            Filtering = true;
        }
        public bool CanExecute_DisplayFilters(object _) => !Filtering;
        public RelayCommand DisplayFilters
        {
            get => displayFilterScreen ?? (displayFilterScreen = new RelayCommand(Execute_DisplayFilters, CanExecute_DisplayFilters));
        }

        private RelayCommand applyFilters;
        public void Execute_ApplyFilters(object _)
        {
            Filtering = !Filtering;
            Notify(nameof(AssignableItems));
            Notify(nameof(Filtered));
            Notify(nameof(ViewTitle));
        }
        public bool CanExecute_ApplyFilters(object _) => Filtering;
        public RelayCommand ApplyFilters
        {
            get => applyFilters ?? (applyFilters = new RelayCommand(Execute_ApplyFilters, CanExecute_ApplyFilters));
        }

        private RelayCommand doAssign;
        public void Execute_Assign(object _)
        {
            UserSelectWindow us = new UserSelectWindow();
            us.Owner = Application.Current.MainWindow;

            ViewModelServer.UserSelectVM.Prompt = "Select the user you wish to assign these items to";
        }
        public bool CanExecute_Assign(object _) => !Filtering && (bool)AssignableItems?.Any(x => x.Selected);
        public RelayCommand Assign
        {
            get => doAssign ?? (doAssign = new RelayCommand(Execute_Assign, CanExecute_Assign));
        }

        private RelayCommand clrSelection;
        public void Execute_ClearSelection(object _)
        {
            AssignableItems?.Where(x => x.Selected).ToList().ForEach(x => x.Selected = false);
        }
        public bool CanExecute_ClearSelection(object _) => (bool)AssignableItems?.Any(x => x.Selected);
        public RelayCommand ClearSelection
        {
            get => clrSelection ?? (clrSelection = new RelayCommand(Execute_ClearSelection, CanExecute_ClearSelection));
        }
        #endregion
        #region Constructors
        
        #endregion
    }
}

Solution

  • The solution was to add a binding for SelectedIndex and set the value to -1 when calling ClearSelection; tip from here