将RibbonComboBox绑定到已过滤的ObservableCollection会导致错误

时间:2019-09-24 10:15:38

标签: c# wpf ribbon-control

我正在使用C#尝试使用RibbonRadioButtons过滤RibbonComboBox列表,但无法解决我不断收到的错误。

国家/地区列表在ObservableCollection中,我正在使用ListCollectionView对其进行过滤。在另一个用户(C# WPF Filter ComboBox based on RadioButtons)的帮助下,我现在可以使其部分工作,但是如果单击单选按钮,则ComboBox中的列表将更新,但是ComboBox中什么都没有显示;我希望显示列表中的第一项。如果选择一个国家,然后从单选按钮中单击另一个大陆,则会在“ public bool Africa {... CountryView.Refresh()}”行或我单击的任何按钮上收到以下显示的错误。 [代码于9月25日更新以反映评论。]

RibbonComboBox错误

Object reference not set to an instance of an object.
In VS Output window:
Error: 40 : BindingExpression path error: 'DisplayName' property not found on 'object'

如下所示,当我在XAML中将RibbonComboBox更改为ComboBox时,尽管它会生成另一个错误,但它似乎可以正常工作。但是,我更喜欢使用RibbonComboBox,但不确定如何解决该问题。您将给予的一切帮助,以使其正常运行。

XAML

<Grid>
    <DockPanel>
        <r:Ribbon DockPanel.Dock="Top" x:Name="Ribbon">
            <r:RibbonGroup Header="Continent" Width="260">
                <!--<ComboBox x:Name="CountryList" Width="100" ItemsSource="{Binding CountryView}" SelectedItem="{Binding SelectedCountry}" DisplayMemberPath="DisplayName"/>-->
                <r:RibbonComboBox x:Name="CountryList" Height="Auto" SelectionBoxWidth="230" VerticalAlignment="Center">
                    <r:RibbonGallery x:Name="cbSelectedCountry" SelectedValue="{Binding SelectedCountry, Mode=TwoWay}" SelectedValuePath="DisplayName" >
                        <r:RibbonGalleryCategory x:Name="cbCountryList" ItemsSource="{Binding CountryView}" DisplayMemberPath="DisplayName" />
                    </r:RibbonGallery>
                </r:RibbonComboBox>
                <WrapPanel>
                    <r:RibbonRadioButton x:Name="All" Label="All" GroupName="ContinentGroup" Height="Auto" Width="Auto" HorizontalAlignment="Left" IsChecked="{Binding Path=All}">
                    </r:RibbonRadioButton>
                    <r:RibbonRadioButton x:Name="Africa" Label="Africa" GroupName="ContinentGroup" Height="Auto" Width="Auto" HorizontalAlignment="Left" IsChecked="{Binding Path=Africa}">
                    </r:RibbonRadioButton>
                    <r:RibbonRadioButton x:Name="America" Label="America" GroupName="ContinentGroup" Height="Auto" Width="Auto" HorizontalAlignment="Left" IsChecked="{Binding Path=America}">
                    </r:RibbonRadioButton>
                </WrapPanel>
            </r:RibbonGroup>
        </r:Ribbon>
    </DockPanel>
</Grid>

(DataContext)后面的C#代码:

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

public class MySettings : INotifyPropertyChanged
{
    private readonly ObservableCollection<Country> countries;
    private ContinentViewModel selectedContinent;
    private static string selectedCountry;
    private int selectedRadioGroup;
    private ObservableCollection<ContinentViewModel> continents;
    private ListCollectionView countryView;
    public event PropertyChangedEventHandler PropertyChanged;
    private bool _All;
    private bool _Africa;
    private bool _America;

    public bool All { get => _All; set { _All = value; CountryView.Refresh(); SelectedCountry = countries[0].ToString(); } }
    public bool Africa { get => _Africa; set { _Africa = value; CountryView.Refresh(); SelectedCountry = countries[0].ToString(); } }
    public bool America { get => _America; set { _America = value; CountryView.Refresh(); SelectedCountry = countries[0].ToString(); } }

    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.Africa, DisplayName = "Chad" },
                new Country() { Continent = Continent.Africa, DisplayName = "Ghana" },
                new Country() { Continent = Continent.America, DisplayName = "Canada" },
                new Country() { Continent = Continent.America, DisplayName = "Greenland" },
                new Country() { Continent = Continent.America, DisplayName = "Haiti" }
            });
        CountryView = (ListCollectionView)CollectionViewSource.GetDefaultView(countries);
        CountryView.Filter += CountryFilter;
        Continents = new ObservableCollection<ContinentViewModel>(Enum.GetValues(typeof(Continent)).Cast<Continent>().Select(c => new ContinentViewModel { Model = c }));
    }

    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 (America) return country.Continent == Continent.America;
        return true;
    }

    public ObservableCollection<ContinentViewModel> Continents
    {
        get { return continents; }
        set
        {
            continents = value;
        }
    }

    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,
        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;
        }
    }

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

1 个答案:

答案 0 :(得分:0)

我已修改您的班级以解决您的问题。代码更改为:

  1. 执行CountryView = new ListCollectionView(countries)而不是CountryView = (ListCollectionView)CollectionViewSource.GetDefaultView(countries)
  2. 每次刷新列表时,即检查CheckBox时,请设置ComboBox的SelectedItem,例如SelectedCountry,如下所示: SelectedCountry = _All ? countries.FirstOrDefault().DisplayName : SelectedCountry; SelectedCountry = _Africa ? countries.Where(_ => _.Continent == Continent.Africa).FirstOrDefault().DisplayName : SelectedCountry; SelectedCountry = _America ? countries.Where(_ => _.Continent == Continent.America).FirstOrDefault().DisplayName : SelectedCountry;
  3. 为所有属性调用OnPropertyChanged

    private readonly ObservableCollection<Country> countries;
    private ContinentViewModel selectedContinent;
    private static string selectedCountry;
    private int selectedRadioGroup;
    private ObservableCollection<ContinentViewModel> continents;
    private ListCollectionView countryView;
    public event PropertyChangedEventHandler PropertyChanged;
    private bool _All;
    private bool _Africa;
    private bool _America;
    public bool All
    {
        get
        {
            return _All;
        }
        set
        {
            _All = value;
            CountryView.Refresh();
            SelectedCountry = _All ? countries.FirstOrDefault().DisplayName : SelectedCountry;
            OnPropertyChanged("All");
        }
    }
    
    public bool Africa
    {
        get
        {
            return _Africa;
        }
        set
        {
            _Africa = value;
            CountryView.Refresh();
            SelectedCountry = _Africa ? countries.Where(_ => _.Continent == Continent.Africa).FirstOrDefault().DisplayName : SelectedCountry;
            OnPropertyChanged("Africa");
        }
    }
    
    public bool America
    {
        get
        {
            return _America;
        }
        set
        {
            _America = value;
            CountryView.Refresh();
            SelectedCountry = _America ? countries.Where(_ => _.Continent == Continent.America).FirstOrDefault().DisplayName : SelectedCountry;
            OnPropertyChanged("America");
        }
    }
    
    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.Africa, DisplayName = "Chad" },
            new Country() { Continent = Continent.Africa, DisplayName = "Ghana" },
            new Country() { Continent = Continent.America, DisplayName = "Canada" },
            new Country() { Continent = Continent.America, DisplayName = "Greenland" },
            new Country() { Continent = Continent.America, DisplayName = "Haiti" }
            });
        CountryView = (ListCollectionView)CollectionViewSource.GetDefaultView(countries);
        CountryView.Filter += CountryFilter;
        Continents = new ObservableCollection<ContinentViewModel>(Enum.GetValues(typeof(Continent)).Cast<Continent>().Select(c => new ContinentViewModel { Model = c }));
    }
    
    private bool CountryFilter(object obj)
    {
        var country = obj as Country;
        if (country == null) return false;
        if (All && !Africa && !America) return true;
        else if (!All && Africa && !America) return country.Continent == Continent.Africa;
        else if (!All && !Africa && America) return country.Continent == Continent.America;
        return true;
    }
    
    public ObservableCollection<ContinentViewModel> Continents
    {
        get { return continents; }
        set
        {
            continents = value;
            OnPropertyChanged("Continents");
        }
    }
    
    public ListCollectionView CountryView
    {
        get { return countryView; }
        set
        {
            countryView = value;
            OnPropertyChanged("CountryView");
        }
    }
    
    public class Country
    {
        public string DisplayName { get; set; }
        public Continent Continent { get; set; }
    }
    
    public enum Continent
    {
        All,
        Africa,
        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;
            OnPropertyChanged("SelectedRadioGroup");
        }
    }
    
    public string SelectedCountry
    {
        get { return selectedCountry; }
        set
        {
            if (selectedCountry == value) return;
            selectedCountry = value;
            OnPropertyChanged("SelectedCountry");
        }
    }
    
    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }