Skip to main content
 首页 » 编程设计

c#之如果以前的记录在 ItemsSource 集合中没有匹配项,则 WPF ComboBox 绑定(bind)有效,如果有则失败

2024年01月01日46qq号

我有以下 WPF 组合框:

<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}}"/> 

CollectionViewSource 的来源是:

public List<MSDExportProxy> Performances 
{ 
  get 
  { 
    if (Portfolio != null) 
    { 
      return (from a in Portfolio.Accounts where a.MSDPortfolioID != null select new MSDExportProxy(a)) 
        .Concat<MSDExportProxy>(from g in Portfolio.Groups where g.MSDPortfolioID != null select new MSDExportProxy(g)) 
        .Concat<MSDExportProxy>(from p in new[] { Portfolio } where p.MSDPortfolioID != null select new MSDExportProxy(p)) 
        .ToList<MSDExportProxy>(); 
    } 
    return new List<MSDExportProxy>(); 
  } 
} 

绑定(bind)属性 PlanPerfID 是一个字符串。

我使用 ListBox 控件在记录之间移动。如果以前的记录在其 ComboBox.ItemsSource 中没有项目,则 ComboBox 工作正常。如果先前记录的 ComboBox.ItemsSource 中有任何项目,则新记录将不会在 ItemsSource 集合中找到其匹配项目。我已经尝试在 XAML 和代码隐藏中设置 ItemsSource,但没有任何改变这种奇怪的行为。我怎样才能让这个该死的东西工作?

请您参考如下方法:

在 Xaml 中处理列表/ObservableCollection 时,尝试将 ICollectionViews 与 IsSynchronizedWithCurrentItem 属性结合使用。 View 模型中的 ICollectionView 可以处理所有需要的东西,例如排序、过滤、跟踪选择和状态。

Xaml:

<Window x:Class="ComboBoxBinding.MainWindow" 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
        <Grid.ColumnDefinitions> 
            <ColumnDefinition /> 
            <ColumnDefinition /> 
        </Grid.ColumnDefinitions> 
        <ListBox Grid.Column="0"  
                 ItemsSource="{Binding Reports}"  
                 DisplayMemberPath="Name"  
                 IsSynchronizedWithCurrentItem="True" /> 
        <ComboBox Grid.Column="1"  
                  ItemsSource="{Binding CurrentReport.Performances}"  
                  DisplayMemberPath="Name"  
                  IsSynchronizedWithCurrentItem="True" /> 
    </Grid> 
</Window> 

View 模型:

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