WPF MVVM: Dictionary<string, bool> Binding Issue (SetProperty Not Triggering)

fatih uyanık 225 Reputation points
2025-04-03T11:32:15.2066667+00:00

Hello

In my WPF MVVM project, I'm using a Dictionary<string, bool> to store filtering options. I'm updating this dictionary using the SetProperty method and binding it to the IsChecked property of RadioButton controls in my UI. However, when the RadioButton selection changes, the SetProperty method is not triggered, and the DataCollectionView is not refreshed.

using CommunityToolkit.Mvvm.Input;
using Kütüphane_Otomasyonu.BusinessLayer.Services.Interfaces;
using Kütüphane_Otomasyonu.BusinessLayer.ViewModels.Base;
using Kütüphane_Otomasyonu.DataLayer.Models;
using Kütüphane_Otomasyonu.PresentationLayer.Views.BorrowedViews;
using System;
using System.Collections.Generic;
namespace Kütüphane_Otomasyonu.BusinessLayer.ViewModels.BorrowedViewModels
{
    public class LoanListingViewModel : BaseListViewModel<BorrowedBook>
    {
        private readonly ILoanListingService loanListingService;
        private readonly INavigationService navigationService;
        public RelayCommand FilterCommand { get; private set; }
        private Dictionary<string, bool> _filters = new()
        {
            {"ShowOverdueOnly", true}
        };
        public Dictionary<string, bool> Filters
        {
            get => _filters;
            set
            {
                if (SetProperty(ref _filters, value))
                {
                    DataCollectionView.Refresh();
                }
            }
        }
        private readonly Dictionary<string, Func<BorrowedBook, bool, bool>> _filterConditions = new Dictionary<string, Func<BorrowedBook, bool, bool>>()
        {
            {"ShowOverdueOnly", (borrowedBook, showOverdueOnly) => showOverdueOnly ? borrowedBook.IsDelivered == DataLayer.Enums.BookStatus.Borrowed && borrowedBook.DueDate < DateTime.Today : true}
        };
        private BorrowedBook _selectedItem;
        public BorrowedBook SelectedItem
        {
            get => _selectedItem;
            set => _selectedItem = value;
        }
        public LoanListingViewModel(ILoanListingService loanListingService, INavigationService navigationService) : base(loanListingService, navigationService)
        {
            this.loanListingService = loanListingService;
            this.navigationService = navigationService;
            Initialize();
        }
        private void Initialize()
        {
            FilterCommand = new RelayCommand(FilterCommandExecute);
            SetFilterAndConditions(Filters, _filterConditions);
        }
        private void FilterCommandExecute()
        {
            DataCollectionView.Refresh();
        }
        protected override void AddCommandExecute()
        {
            // Add operation
        }
        protected override void OnItemClickedCommandExecute(object obj)
        {
            if (obj is BorrowedBook borrowedBook)
            {
                _selectedItem = borrowedBook;
                navigationService.NavigateToView<LendDetailView>(_selectedItem);
            }
        }
    }
}
<Page
    x:Class="Kütüphane_Otomasyonu.PresentationLayer.Views.BorrowedViews.LoanListingView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:loanlistingviewmodels="clr-namespace:Kütüphane_Otomasyonu.BusinessLayer.ViewModels.BorrowedViewModels"
    xmlns:usercontrols="clr-namespace:Kütüphane_Otomasyonu.PresentationLayer.Views.UserControls"
    mc:Ignorable="d"
    d:DesignHeight="450" d:DesignWidth="800"
    Title="Ödünç Listesi"
    d:DataContext="{d:DesignInstance Type=loanlistingviewmodels:LoanListingViewModel, IsDesignTimeCreatable=True}">
    <usercontrols:ListUserControl
        ListTitle="Ödünç Listesi"
        ItemsSource="{Binding DataCollectionView}"
        ItemClickedCommand="{Binding ItemClickedCommand}">
        <usercontrols:ListUserControl.Columns>
            <GridViewColumn Header="Reader" DisplayMemberBinding="{Binding Reader.Name}" />
            <GridViewColumn Header="Book" DisplayMemberBinding="{Binding Book.Name}" />
        </usercontrols:ListUserControl.Columns>
        <usercontrols:ListUserControl.Filter>
            <StackPanel
                KeyboardNavigation.DirectionalNavigation="Cycle"
                KeyboardNavigation.TabNavigation="Once"
                Orientation="Vertical">
                <RadioButton
                    Content="All Loans"
                    GroupName="Filter"
                    IsChecked="{Binding Filters[ShowOverdueOnly], Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
                <RadioButton
                    Content="Overdue Loans"
                    GroupName="Filter"
                    IsChecked="{Binding Filters[ShowOverdueOnly], Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
                <Button Command="{Binding FilterCommand}"/>
            </StackPanel>
        </usercontrols:ListUserControl.Filter>
    </usercontrols:ListUserControl>
</Page>

Problem: The SetProperty method is not triggered when the RadioButton selection changes, and the DataCollectionView is not refreshed.

Attempts: Converted the Filters dictionary to Dictionary<string, bool>.

Verified the correct usage of the SetProperty method.

Checked the UI binding.

Performed debugging steps.

Question:

How can I resolve this issue? What could be causing the SetProperty method not to trigger and the DataCollectionView not to refresh?

Thanks.

Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,853 questions
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Jiale Xue - MSFT 49,831 Reputation points Microsoft External Staff
    2025-04-04T00:50:35.0966667+00:00

    Hi @fatih uyanık , Welcome to Microsoft Q&A,

    WPF's data binding system cannot monitor changes to the value of a key inside a dictionary. It can only monitor changes to the property itself (i.e. whether the entire dictionary has been replaced), not changes to the value of a key in the dictionary.

    Add a separate property to ShowOverdueOnly.

    public bool ShowOverdueOnly
    {
        get => Filters.TryGetValue("ShowOverdueOnly", out var value) && value;
        set
        {
            if (Filters["ShowOverdueOnly"] != value)
            {
              Filters["ShowOverdueOnly"] = value;
              OnPropertyChanged(); // Notify property changes
              DataCollectionView.Refresh(); // Refresh the list
            }
        }
    }
    

    Edit the XML:

    <RadioButton
        Content="All Loans"
        GroupName="Filter"
        IsChecked="{Binding ShowOverdueOnly, Converter={StaticResource InverseBooleanConverter}, Mode=TwoWay}" />
    
    <RadioButton
        Content="Overdue Loans"
        GroupName="Filter"
        IsChecked="{Binding ShowOverdueOnly, Mode=TwoWay}" />
    
    

    Best Regards,

    Jiale


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment". 

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.