0

I have a WPF project with a Ribbon ComboBox showing a list of countries that I'm trying to filter depending upon a selected RadioButton option (All, Africa, Asia, Europe). I'm basing my code on COMBOBOX filtering in WPF with MVVM which uses a ComboBox to select a continent and show the filtered countries in a ListBox but I'm having trouble converting this to use RadioButtons.

  1. There's a problem with the XAML isChecked="..." lines which appear to cause an 'Input string was not in a correct format' error in the EnumBooleanConverter but if I change them to 'ConverterParameter=0' the app runs. I based this on How to bind RadioButtons to an enum?.
  2. The default list of countries is initially shown in the ComboBox but the default country isn't displayed, instead it's blank.
  3. Clicking on a RadioButton has no effect on the list.

Clearly I'm doing something wrong but I don't know what. Can you help?

XAML:

<ribbon:RibbonRadioButton x:Name="AllContinents"
   GroupName="Continents"
   IsChecked="{Binding Path=SelectedRadioGroup, Converter={StaticResource EnumBooleanConverter}, ConverterParameter={x:Static local:mySettings+Continent.All}}"> <= Causes run error
</ribbon:RibbonRadioButton>

<ribbon:RibbonRadioButton x:Name="Africa"
   GroupName="Continents"
   IsChecked="{Binding Path=SelectedRadioGroup, Converter={StaticResource EnumBooleanConverter}, ConverterParameter={x:Static local:mySettings+Continent.Africa}}"> <= Causes run error
</ribbon:RibbonRadioButton>

C# Code behind (DataContext):

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Data;

public class MySettings : INotifyPropertyChanged
{
    private ObservableCollection<Country> countries;
    private ContinentViewModel selectedContinent;
    public ListCollectionView CountryView { get; set; }
    public event PropertyChangedEventHandler PropertyChanged;
    public ObservableCollection<ContinentViewModel> Continents { get; set; } 
    private static string selectedCountry = "Germany"; // Default country

    public MySettings()
    {
        countries =
            new ObservableCollection<Country>(
                new[]
                    {
                        new Country() { Continent = Continent.Africa, DisplayName = "Algeria" },
                        new Country() { Continent = Continent.Africa, DisplayName = "Egypt" },
                        new Country() { Continent = Continent.Europe, DisplayName = "France" }
                        new Country() { Continent = Continent.Europe, DisplayName = "Germany" }
                    });
        CountryView = new ListCollectionView(countries);
        CountryView.Filter = o => selectedContinent == null || ((Country)o).Continent == selectedContinent.Model;

        Continents = new ObservableCollection<ContinentViewModel>(Enum.GetValues(typeof(Continent)).Cast<Continent>().Select(c => new ContinentViewModel { Model = c}));
    }

    public ListCollectionView CountryView
    {
        get { return countryView; }
        set
        {
            countryView = value;
        }
    }

    public class Country
    {
        public string DisplayName { get; set; }
        public Continent Continent { get; set; }
    }

    public enum Continent
    {
        All,
        Africa,
        Asia,
        Europe,
        America
    }

    public class ContinentViewModel
    {
        public Continent Model { get; set; }
        public string DisplayName
        {
            get
            {
                return Enum.GetName(typeof(Continent), Model);
            }
        }
    }

    public ContinentViewModel SelectedContinent
    {
        get { return selectedContinent; }
        set
        {
            selectedContinent = value;
            OnContinentChanged();
            this.OnPropertyChanged("SelectedContinent");
        }
    }

    private void OnContinentChanged()
    {
        CountryView.Refresh();
    }

    public int SelectedRadioGroup
    {
        get { return selectedRadioGroup; }
        set
        {
            selectedRadioGroup = value;
        }
    }

    public string SelectedCountry
    {
        get { return selectedCountry; }
        set
        {
            if (selectedCountry == value) return;
            selectedCountry = value;
            OnPropertyChanged(nameof(SelectedCountry));
        }
    }

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = this.PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

public class EnumBooleanConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
      int integer = (int)value;
      return integer == int.Parse(parameter.ToString()) ? true : (object)false;  <= Error:Input string was not in a correct format
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return ((bool)value) ? parameter : Binding.DoNothing;
    }
}
Leo371
  • 3
  • 4

1 Answers1

0

I would have a bool property for each radio button rather than using an converter. Then do the check in your filter.

CountryView.Filter += CountryFilter;

private bool _All;
private bool _Africa;
private bool _Asia;
private bool _Europe;
private bool _America;

public bool All { get=>_All; set { _All=value; CountryView.Refresh(); } }
public bool Africa { get=> _Africa; set { _Africa=value; CountryView.Refresh(); } }
public bool Asia { get=> _Asia; set { _Asia=value; CountryView.Refresh(); } }
public bool Europe { get=> _Europe; set { _Europe=value; CountryView.Refresh(); } }
public bool America { get=> _America; set { _America=value; CountryView.Refresh() ;} }}

private bool CountryFilter(object obj)
{
    var country = obj as Country;
    if (country== null) return false;
    if (All) return true;
    if (Africa) return country.Continent == Continent.Africa;
    if (Asia) return country.Continent == Continent.Asia;
    if (Europe) return country.Continent == Continent.Europe;
    if (America) return country.Continent == Continent.America;
    return true;
}
Neil B
  • 2,096
  • 1
  • 12
  • 23
  • I added your code and changed `CountryView.Filter = o => selectedContinent == null || ((Country)o).Continent == selectedContinent.Model;` to read `CountryView.Filter += CountryFilter;` In the XAML I changed the `IsChecked...` to read `IsChecked="{Binding Path=Africa}"` but the ComboBox is still not filtered. – Leo371 Sep 16 '19 at 13:19
  • You would need to refresh the view in the property setter. I've changed my example. – Neil B Sep 16 '19 at 17:50
  • Thanks for the update. The ComboBox is now updated and displays the correct countries. However if I select a country then click on a RadioButton I get an error: `Object reference not set to an instance of an object` at `CountryView.Refresh()` and `Error: 40 : BindingExpression path error: 'DisplayName' property not found on 'object' ''String' (HashCode=1228963566)'. BindingExpression:Path=DisplayName; DataItem='String' (HashCode=1228963566); target element is 'DummyObject' (Name=''); target property is 'Content' (type 'Object')`. – Leo371 Sep 17 '19 at 10:38