将 RibbonComboBox 绑定到过滤后的 ObservableCollection 导致错误
Binding a RibbonComboBox to filtered ObservableCollection causing errors
我正在使用 C# 尝试使用 RibbonRadioButtons 过滤 RibbonComboBox 列表,但我无法解决不断收到的错误。
国家列表在我使用 ListCollectionView 过滤的 ObservableCollection 中。在另一个用户 (C# WPF Filter ComboBox based on RadioButtons) 的帮助下,我现在可以部分工作,但是如果我单击单选按钮,组合框中的列表会更新,但组合框中没有显示任何内容;我希望显示列表中的第一项。如果我 select 一个国家,然后从 RadioButton 单击另一个大陆,我会在 '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>
C# 代码隐藏 (DataContext):
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));
}
}
我已经修改了你的 class 来解决你的问题。代码的变化是:
- 代替
CountryView = new ListCollectionView(countries)
做CountryView = (ListCollectionView)CollectionViewSource.GetDefaultView(countries)
- 在每次刷新列表时,即检查
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;
为所有属性调用 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));
}
我正在使用 C# 尝试使用 RibbonRadioButtons 过滤 RibbonComboBox 列表,但我无法解决不断收到的错误。
国家列表在我使用 ListCollectionView 过滤的 ObservableCollection 中。在另一个用户 (C# WPF Filter ComboBox based on RadioButtons) 的帮助下,我现在可以部分工作,但是如果我单击单选按钮,组合框中的列表会更新,但组合框中没有显示任何内容;我希望显示列表中的第一项。如果我 select 一个国家,然后从 RadioButton 单击另一个大陆,我会在 '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>
C# 代码隐藏 (DataContext):
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));
}
}
我已经修改了你的 class 来解决你的问题。代码的变化是:
- 代替
CountryView = new ListCollectionView(countries)
做CountryView = (ListCollectionView)CollectionViewSource.GetDefaultView(countries)
- 在每次刷新列表时,即检查
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;
为所有属性调用
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)); }