Home > Software design >  WPF - MVVM: Checkboxes are not rendering correctly
WPF - MVVM: Checkboxes are not rendering correctly

Time:03-29

I'm a newcomer to WPF and the MVVM-Model, so I hope my problem can be fixed very easily. To summarize it at the beginning: My Checkboxes inside my UserControl don't represent their checked-states correctly.

I want to implement a whole bunch of Checkboxes to realize map filters inside a side-panel, similar to Google Earth. To achieve that, I created a simple MapFilter class, which holds the filters name and status (is it active or not)

public class MapFilter : ObservableObject
{
    private bool _active;
    public string Name { get; }

    public bool Active
    {
        get => _active;
        set
        {
            if (_active != value)
            {
                _active = value;
                OnPropertyChanged();
            }
        }
    }

    public MapFilter(string name, bool active = false)
    {
        Name = name;
        Active = active;
    }
}

ObservableObject is the implementation of the INotifyPropertyChanged-Interface

public class ObservableObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler? PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
    {
        if(!string.IsNullOrEmpty(propertyName))
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

So I put some of these MapFilters inside a Model-class for my side-panel

public class MapFiltersModel
{
    public MapFilter PopByTribeFilter { get; set; }
    public MapFilter CountriesFilter { get; set; }
    public MapFilter LifeStandardFilter { get; set; }
    public MapFilter UrbanizationFilter { get; set; }

    public MapFiltersModel()
    {
        PopByTribeFilter = new MapFilter(Resources.Localization.Locals_German.mapfilters_popByTribe, true);
        CountriesFilter = new MapFilter(Resources.Localization.Locals_German.mapfilters_countries);
        LifeStandardFilter = new MapFilter(Resources.Localization.Locals_German.mapfilters_lifeStandard);
        UrbanizationFilter = new MapFilter(Resources.Localization.Locals_German.urbanization);
    }
}

and put THIS MapFiltersModel inside a ViewModel.

public class MapFiltersViewModel : ObservableObject
{
    private readonly MapFiltersModel _model;

    public MapFiltersModel Model
    {
        get => _model;
        private init
        {
            if (_model.Equals(value))
                return;

            _model = value;
            OnPropertyChanged();
        }
    }

    public MapFiltersViewModel()
    {
        _model = new MapFiltersModel();
        Model = _model;
    }
}

Finally, this is the XAML for my side-panel with the Checkboxes.

<UserControl x:Class="SimulateTheWorld.GUI.Controls.SidePanel.Panels.MapFiltersControl"
             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:mapFilters="clr-namespace:SimulateTheWorld.ViewModels.SidePanel.Panels.MapFilters;assembly=SimulateTheWorld.ViewModels"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="400">
    <UserControl.DataContext>
        <mapFilters:MapFiltersViewModel/>
    </UserControl.DataContext>

    <Grid>
        <StackPanel x:Name="tv_mapFilters" Background="Transparent" Margin="10,5">
            <CheckBox IsChecked="{Binding Model.PopByTribeFilter.Active, UpdateSourceTrigger=PropertyChanged}" 
                      Content="{Binding Model.PopByTribeFilter.Name}"/>
            <CheckBox IsChecked="{Binding Model.CountriesFilter.Active, UpdateSourceTrigger=PropertyChanged}" 
                      Content="{Binding Model.CountriesFilter.Name}"/>
            <CheckBox IsChecked="{Binding Model.LifeStandardFilter.Active, UpdateSourceTrigger=PropertyChanged}" 
                      Content="{Binding Model.LifeStandardFilter.Name}"/>
            <CheckBox IsChecked="{Binding Model.UrbanizationFilter.Active, UpdateSourceTrigger=PropertyChanged}" 
                      Content="{Binding Model.UrbanizationFilter.Name}"/>
        </StackPanel>
    </Grid>
</UserControl>

The problem now is the following:

I checked if I can activate all these MapFilters and I saw (via debugging of course), that the Active-Properies inside the MapFilter-classes are set and saved correctly. The setters are jumped into perfectly fine, also the PropertyChanged-events are triggered and the getters give the correct results. But I cannot see any checkmarks in my Checkboxes.

I also tested if my bindings towards the Model and ViewModel are working. So I created a TextBox for user input and a Label, which shows the user input in all capital letters. Works perfectly. So now I'm out of ideas why my checkboxes don't show there checked-states.

Any ideas?

CodePudding user response:

I checked your code and it seems no problem, can you explain your problem more obviously?

enter image description here

Do you use any UI Framework or custom style?

  • Related