C# 如果上一条记录在ItemsSource集合中没有匹配项,则WPF ComboBox绑定工作,如果有匹配项,则绑定失败
我有以下WPF组合框:C# 如果上一条记录在ItemsSource集合中没有匹配项,则WPF ComboBox绑定工作,如果有匹配项,则绑定失败,c#,wpf,xaml,combobox,null,C#,Wpf,Xaml,Combobox,Null,我有以下WPF组合框: <Window.Resources> <CollectionViewSource x:Key="performanceItemsource" Source="{Binding Path=SelectedReport.Performances}" > <CollectionViewSource.SortDescriptions> <scm:SortDescription Proper
<Window.Resources>
<CollectionViewSource x:Key="performanceItemsource" Source="{Binding Path=SelectedReport.Performances}" >
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="Name"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
</Window.Resources>
...
<ComboBox Name="cbxPlanPerf" Grid.ColumnSpan="2"
SelectedValuePath="MSDPortfolioID" DisplayMemberPath="Name"
SelectedValue="{Binding Path=PlanPerfID}"
ItemsSource="{Binding Source={StaticResource performanceItemsource}}"/>
绑定属性PlanPerfID
是一个字符串
我使用列表框控件在记录之间移动。如果前一条记录的ComboBox.ItemsSource中没有任何项,则ComboBox工作正常。如果以前记录的ComboBox.ItemsSource中有任何项,则新记录将无法在
ItemsSource
集合中找到其匹配项。我尝试在XAML和代码隐藏中设置ItemsSource
,但没有改变这种奇怪的行为。我如何才能让这个该死的东西正常工作?在Xaml中处理列表/ObservableCollection时,尝试将ICollectionView
与IsSynchronizedWithCurrentItem
属性结合使用。viewmodel中的ICollectionView可以处理所有需要的事情,例如排序、过滤、跟踪选择和状态
Xaml:
视图模型:
public class ViewModel : INotifyPropertyChanged
{
private readonly IReportService _reportService;
private ObservableCollection<ReportViewModel> _reports = new ObservableCollection<ReportViewModel>();
private PerformanceViewModel _currentPerformance;
private ReportViewModel _currentReport;
public ObservableCollection<ReportViewModel> Reports
{
get { return _reports; }
set { _reports = value; OnPropertyChanged("Reports");}
}
public ReportViewModel CurrentReport
{
get { return _currentReport; }
set { _currentReport = value; OnPropertyChanged("CurrentReport");}
}
public PerformanceViewModel CurrentPerformance
{
get { return _currentPerformance; }
set { _currentPerformance = value; OnPropertyChanged("CurrentPerformance");}
}
public ICollectionView ReportsView { get; private set; }
public ICollectionView PerformancesView { get; private set; }
public ViewModel(IReportService reportService)
{
if (reportService == null) throw new ArgumentNullException("reportService");
_reportService = reportService;
var reports = _reportService.GetData();
Reports = new ObservableCollection<ReportViewModel>(reports);
ReportsView = CollectionViewSource.GetDefaultView(Reports);
ReportsView.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
ReportsView.CurrentChanged += OnReportsChanged;
ReportsView.MoveCurrentToFirst();
}
private void OnReportsChanged(object sender, EventArgs e)
{
var selectedReport = ReportsView.CurrentItem as ReportViewModel;
if (selectedReport == null) return;
CurrentReport = selectedReport;
if(PerformancesView != null)
{
PerformancesView.CurrentChanged -= OnPerformancesChanged;
}
PerformancesView = CollectionViewSource.GetDefaultView(CurrentReport.Performances);
PerformancesView.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
PerformancesView.CurrentChanged += OnPerformancesChanged;
PerformancesView.MoveCurrentToFirst();
}
private void OnPerformancesChanged(object sender, EventArgs e)
{
var selectedperformance = PerformancesView.CurrentItem as PerformanceViewModel;
if (selectedperformance == null) return;
CurrentPerformance = selectedperformance;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
公共类视图模型:INotifyPropertyChanged
{
专用只读IReportService\u reportService;
私有ObservableCollection_reports=新ObservableCollection();
私人绩效eviewModel\u currentPerformance;
private ReportViewModel\u currentReport;
公开收集报告
{
获取{return\u reports;}
设置{u reports=value;OnPropertyChanged(“reports”);}
}
公共报告视图模型当前报告
{
获取{return\u currentReport;}
设置{u currentReport=value;OnPropertyChanged(“currentReport”);}
}
公共性能虚拟模型当前性能
{
获取{return\u currentPerformance;}
设置{u currentPerformance=value;OnPropertyChanged(“currentPerformance”);}
}
公共ICollectionView报告视图{get;private set;}
公共ICollectionView性能视图{get;private set;}
公共视图模型(IReportService reportService)
{
如果(reportService==null)抛出新的ArgumentNullException(“reportService”);
_reportService=reportService;
var reports=_reportService.GetData();
报告=新的可观察收集(报告);
ReportsView=CollectionViewSource.GetDefaultView(报告);
ReportsView.SortDescriptions.Add(新的SortDescription(“Name”,ListSortDirection.升序));
ReportsView.CurrentChanged+=OnReportsChanged;
ReportsView.MoveCurrentToFirst();
}
私有void OnReportsChanged(对象发送方,事件参数e)
{
var selectedReport=ReportsView.CurrentItem作为ReportViewModel;
if(selectedReport==null)返回;
CurrentReport=selectedReport;
如果(PerformanceView!=null)
{
PerformanceView.CurrentChanged-=OnPerformanceChanged;
}
PerformancesView=CollectionViewSource.GetDefaultView(CurrentReport.Performances);
PerformanceView.SortDescriptions.Add(新的SortDescription(“名称”,ListSortDirection.升序));
PerformanceView.CurrentChanged+=OnPerformanceChanged;
PerformanceView.MoveCurrentToFirst();
}
private void onPerformanceChanged(对象发送方,事件参数e)
{
var selectedperformance=PerformanceView.CurrentItem作为PerformanceView模型;
if(selectedperformance==null)返回;
CurrentPerformance=所选性能;
}
公共事件属性更改事件处理程序属性更改;
受保护的虚拟void OnPropertyChanged(字符串propertyName)
{
PropertyChangedEventHandler处理程序=PropertyChanged;
if(handler!=null)handler(这是新的PropertyChangedEventArgs(propertyName));
}
}
我找到了一个快速而肮脏的解决方案。我只是碰巧在我的报表实体上有一个publicNotifyPropertyChanged()
方法,我发现如果我调用SelectedReport.NotifyPropertyChanged(“PlanPerfID”)
在报告列表框的选择更改的事件中,震动足以使组合框
重新评估并在项目资源
中找到匹配的项目。是的,是克鲁格
更新:对于某些情况,我还需要添加SelectedReport.NotifyPropertyChanged(“性能”)
更新2:好吧,原来上面的不是防弹的,我遇到了一个破坏它的情况,所以我必须想出一个更好的解决办法:
更改了窗口的“代码隐藏”中的SelectedReport
属性,添加了一个私有标志(\u settingCombos
),以防止绑定扭曲绑定值,直到项源中的灰尘沉降下来:
private bool _settingCombos = false;
private Report _SelectedReport;
public Report SelectedReport
{
get { return _SelectedReport; }
set
{
_settingCombos = true;
_SelectedReport = value;
NotifyPropertyChanged("SelectedReport");
}
}
在“代码隐藏”窗口中创建了一个要绑定的代理,如果\u settingCombos
标志为true
,该代理将拒绝更新属性的值:
public string PlanPerfID_Proxy
{
get { return SelectedReport.PlanPerfID; }
set
{
if (!_settingCombos)
{
SelectedReport.PlanPerfID = value;
NotifyPropertyChanged("PlanPerfID_Proxy");
}
}
}
在报告列表框的SelectionChanged
事件中添加了额外的通知,以及将\u settingCombos
标志重置回false
的代码:
private void lbxReports_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
//KLUGE: Couldn't get the ComboBoxes associated with these properties to work right
//this forces them to re-evaluate after the Report has loaded
if (SelectedReport != null)
{
NotifyPropertyChanged("PlanPerfID_Proxy");
_settingCombos = false;
}
}
将组合框
绑定到PlanPerfID\u代理
属性(而不是直接绑定到SelectedReport.PlanPerfID
属性)
哇,太麻烦了!我认为这只是.NET的绑定逻辑被
组合框.ItemSource
的动态特性弄糊涂的一个例子,但这似乎已经解决了它。希望它能帮助其他人。哇,这与我目前的工作方式有很大的范式转变。看起来你会让我把这个ViewModel cod
public string PlanPerfID_Proxy
{
get { return SelectedReport.PlanPerfID; }
set
{
if (!_settingCombos)
{
SelectedReport.PlanPerfID = value;
NotifyPropertyChanged("PlanPerfID_Proxy");
}
}
}
private void lbxReports_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
//KLUGE: Couldn't get the ComboBoxes associated with these properties to work right
//this forces them to re-evaluate after the Report has loaded
if (SelectedReport != null)
{
NotifyPropertyChanged("PlanPerfID_Proxy");
_settingCombos = false;
}
}