Search code examples
c#wpfxamlvisibilityobservablecollection

WPF change visibility based on Items in Observable-Collection


I have the Following Collection: ObservableCollection<CheckedFileObject> Files

A CheckedFileObject contains a FileObject and a bool isChecked. Now when a user selects a File the isChecked Value of this file gets changed to true.

If at least one CheckedFileObject contains IsChecked = true, i want to make the Delete Button Visible.

So my Question is, is it possible to toggle the visibility based on an item in an ObservableCollection and how? I doesn't matter how many items there are, but if one is checked the button should be visible.

Maybe something like:

 Visibility="{Binding Files[i].IsChecked, Mode=OneWay, Converter={StaticResource BooleanAndToVisibilityConverter}}"

Or perhaps binding the ObservablCollection to a bool in the viewmodel which gets updated through something like this:

var isVisible = Files.Any(x => x.IsChecked == true);

when the collection changes. Is this even possible?


Solution

  • you can get the feature of items tracking from ListCollectionView class and change Button.Visibility based on item count in that collection view:

    public ObservableCollection<CheckedFileObject> Files { get; } = new ObservableCollection<CheckedFileObject>();
    
    private ICollectionView _filteredFiles;
    public ICollectionView FilteredFiles 
    {
        get
        {
            if (_filteredFiles == null)
            {
                _filteredFiles = new ListCollectionView(Files)
                {
                    IsLiveFiltering = true,
                    LiveFilteringProperties = { nameof(CheckedFileObject.IsChecked) },
                    Filter = (o) => o is CheckedFileObject file && file.IsChecked
                };
            }
            return _filteredFiles;
        }
    }
    

    Items are displayed from the original collection. Button is bound to the filtered collection:

    <ItemsControl ItemsSource="{Binding Files}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <CheckBox IsChecked="{Binding Path=IsChecked}"/>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
    
    <Button Content="Delete">
        <Button.Style>
            <Style TargetType="Button">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Path=FilteredFiles.Count}" Value="0">
                        <Setter Property="Visibility" Value="Collapsed"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Button.Style>
    </Button>
    

    CheckedFileObject class must have property change notifications (implement INotifyPropertyChanged):

    public class CheckedFileObject : INotifyPropertyChanged
    {
        private bool isChecked;
    
        public bool IsChecked 
        { 
            get => isChecked; 
            set 
            {
                isChecked = value; 
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsChecked)));
            }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
    }