WPF 组合框对更改不具有约束力

WPF combo box not binding on change

我有 3 个组合框

<Grid>
   <ComboBox Name="cbo1" SelectionChanged="OnComboBoxChanged" />
   <ComboBox Name="cbo2" SelectionChanged="OnComboBoxChanged"/>
   <ComboBox Name="cbo3" SelectionChanged="OnComboBoxChanged" />

组合框的列表是{a,b,c,d} 因此,如果在第一个框中选择了 "b",则下拉菜单不应包含 b,如果第二个设置为 a,则需要使用 {a,c,d} 进行更新,那么最后一个需要包含 {光盘}。如果他们回去更改任何内容,我们需要相应地更新列表。我添加了一个 oncomboboxchanged 事件,但当我将项目源设置为新列表时,它没有更新组合框。

private List<string> comboList = new List<string>();
string[] defaultParam = { "A", "B", "C", "D" };

public MainWindow()
{   
       InitializeComponent();
       foreach(string s in defaultParam)
       {
           LoadCombo(s);
       } 

}
public void LoadCombo(string name)
{
   comboList.Add(name); 
   cbo1.ItemsSource = comboList;
   cbo2.ItemsSource = comboList;
   cbo3.ItemsSource = comboList;
}
private void OnComboBoxChanged(object sender,SelectionChangedEventArgs e)
{
   var combo = sender as ComboBox;
   string oldval = combo.Text;
   string id = combo.Name;
   string itemSel = (sender as ComboBox).SelectedItem.ToString();
   comboList.Remove(itemSel);
   //add old value only if it is not empty
   if (!string.IsNullOrEmpty(oldval))
   {
      comboList.Add(oldval);
   }
   combo.ItemsSource = comboList;
   ComboBox[] comboNameLst = {cbo1,cbo2,cbo3 }; 
   foreach (ComboBox cbo in comboNameLst)
   {
       if (id != cbo.Name)
       {
          if (cbo.SelectedItem == null)
          {
              cbo.ItemsSource = comboList;
          }
          else if (cbo.SelectedItem != null)
          {
             string tempitemsel = cbo.SelectedItem.ToString();
             comboList.Add(tempitemsel);
             cbo.ItemsSource = comboList;
             comboList.Remove(tempitemsel);
          }
       }
   }
}

所以 cbo.ItemSource 没有做任何事情,我是否需要做任何不同的事情才能看到更新。

  1. 您需要在 XAML 中使用绑定,而不是在后面的代码中设置 ItemsSource。还有数据绑定 SelectedItem

     <Grid>
         <ComboBox ItemsSource="{Binding DefaultList}" SelectedItem="{Binding SelectedItem_Cob1}"/>
         <ComboBox ItemsSource="{Binding FilteredListA}" SelectedItem="{Binding SelectedItem_Cob2}"/>
         <ComboBox ItemsSource="{Binding FilteredListB}" SelectedItem="{Binding SelectedItem_Cob3}"/>
     </Grid>
    
  2. 在你后面的代码中,你需要实现INotifyPropertyChanged;将相关的 ItemsSources 和 SlectedItems 定义为属性;并将 Windows 的 DataContext 设置为您的代码本身(您应该使用 MVVM 模式,但稍后您可能会担心):

    using System.ComponentModel;
    public partial class MainWindow: INotifyPropertyChanged
    { 
        string[] defaultParam = { "A", "B", "C", "D" };
        private string _selecteditem_cob1;
        private string _selecteditem_cob2;
        private string _selecteditem_cob3;
    
        public List<string> DefaultList
        {
            get { return defaultParam.ToList(); }
        }
    
        public string SelectedItem_Cob1
        {
            get { return _selecteditem_cob1; }
            set
            {
                if (_selecteditem_cob1 != value)
                {
                    _selecteditem_cob1 = value;
                    RaisePropertyChanged("SelectedItem_Cob1");
                    RaisePropertyChanged("FilteredListA");
                    RaisePropertyChanged("FilteredListB");
                }
            }
        }
    
        public string SelectedItem_Cob2
        {
            get { return _selecteditem_cob2; }
            set
            {
                if (_selecteditem_cob2 != value)
                {
                    _selecteditem_cob2 = value;
                    RaisePropertyChanged("SelectedItem_Cob2");
                    RaisePropertyChanged("FilteredListB");
                }
            }
        }
    
        public string SelectedItem_Cob3
        {
            get { return _selecteditem_cob3; }
            set
            {
                if (_selecteditem_cob3 != value)
                {
                    _selecteditem_cob3 = value;
                    RaisePropertyChanged("SelectedItem_Cob3");
                }
            }
        }
    
        public List<string> FilteredListA
        {
            get { return defaultParam.ToList().Where(a=>a!=SelectedItem_Cob1).ToList(); }
        }
        public List<string> FilteredListB
        {
            get { return FilteredListA.Where(a => a != SelectedItem_Cob2).ToList(); }
        }
        public MainWindow()
        {
    
            InitializeComponent();  
            this.DataContext=this;          
        }
    
        //Implementation for INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
    
        protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            var handler = this.PropertyChanged;
            if (handler != null)
            {
                handler(this, e);
            }
        }
    
        protected void RaisePropertyChanged(String propertyName)
        {
            OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
        }
    }
    

结果:

Three ComboBoxes will all show A,B,C,D at the initial stage. And then if user made selections cbo2 and cbo3 will only display filtered result dynamically.

I realized this is not 100% what you want (thanks to @TheodosiusVonRichthofen), but I feel you can still use this, and be able to easily modify it to suit your needs.

此外,包含组合框项目的列表应该是 ObservableCollection 而不是 List。通过将其设为 ObservableCollection,组合框项目将在列表中 add/remove/change 项时更新。