如何在wpf中将两个组合框绑在一起

时间:2013-11-14 10:13:43

标签: c# wpf mvvm binding combobox

我有2个组合框,一个包含'Items'列表,另一个包含'Subitems'列表。

子项列表取决于当前选择的项目。

我已经完成了大部分工作(通过将Subitems的ItemSource绑定到PossibleSubitems属性),但问题是当我更改Item并且Subitem对新项目不再有效时。在这种情况下,我只想选择第一个有效的子项目,但我得到一个空白的组合框。请注意,我认为类中的属性设置正确,但绑定似乎没有正确反映它。

这里有一些代码可以告诉你我在做什么。在这种情况下,我有: 'Item 1',可以有SubItem A或Subitem B和 '第2项'可以有SubItem B或Subitem C

当我选择了Subitem A时切换到第2项时会出现问题。

XAML

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="134" Width="136">
  <StackPanel Height="Auto" Width="Auto">
    <ComboBox ItemsSource="{Binding PossibleItems, Mode=OneWay}" Text="{Binding CurrentItem}"/>
    <ComboBox ItemsSource="{Binding PossibleSubitems, Mode=OneWay}" Text="{Binding CurrentSubitem}"/>
  </StackPanel>
</Window>

代码背后:

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

namespace WpfApplication1
{
  public partial class MainWindow : Window, INotifyPropertyChanged
  {
    // List of potential Items, used to populate the options for the Items combo box
    public ObservableCollection<string> PossibleItems
    {
      get
      {
        ObservableCollection<string> retVal = new ObservableCollection<string>();
        retVal.Add("Item 1");
        retVal.Add("Item 2");
        return retVal;
      }
    }

    // List of potential Items, used to populate the options for the Subitems combo box
    public ObservableCollection<string> PossibleSubitems
    {
      get
      {
        ObservableCollection<string> retVal = new ObservableCollection<string>();
        if (CurrentItem == PossibleItems[0])
        {
          retVal.Add("Subitem A");
          retVal.Add("Subitem B");
        }
        else
        {
          retVal.Add("Subitem B");
          retVal.Add("Subitem C");
        }
        return retVal;
      }
    }

    // Track the selected Item
    private string _currentItem;
    public string CurrentItem
    {
      get { return _currentItem; }
      set
      {
        _currentItem = value;
        // Changing the item changes the possible sub items
        NotifyPropertyChanged("PossibleSubitems");
      }
    }

    // Track the selected Subitem
    private string _currentSubitem;
    public string CurrentSubitem
    {
      get { return _currentSubitem; }
      set
      {
        if (PossibleSubitems.Contains(value))
        {
          _currentSubitem = value;
        }
        else
        {
          _currentSubitem = PossibleSubitems[0];
          // We're not using the valuie specified, so notify that we have in fact changed
          NotifyPropertyChanged("CurrentSubitem");
        }
      }
    }


    public MainWindow()
    {
      InitializeComponent();

      this.DataContext = this;
      CurrentItem = PossibleItems[0];
      CurrentSubitem = PossibleSubitems[0];
    }

    public event PropertyChangedEventHandler PropertyChanged;
    internal void NotifyPropertyChanged(String propertyName = "")
    {
      if (PropertyChanged != null)
      {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
      }
    }

  }
}

2 个答案:

答案 0 :(得分:2)

我重写了我自己的样本 - 保留了代码,以免过多地偏离你的样本。此外,我使用的是.NET 4.5,因此无需在OnPropertyChanged调用中提供属性名称 - 如果在.NET 4.0上,则需要插入它们。这适用于所有情况。

实际上,我建议根据MVVM模式在视图模型中查找此代码。除了DataContext的绑定之外,它与这个实现看起来并没有太大的不同。

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;

namespace WpfApplication1
{
    public partial class MainWindow: Window, INotifyPropertyChanged
    {
        private string _currentItem;
        private string _currentSubitem;
        private ObservableCollection<string> _possibleItems;
        private ObservableCollection<string> _possibleSubitems;

        public MainWindow()
        {
            InitializeComponent();

            LoadPossibleItems();
            CurrentItem = PossibleItems[0];

            UpdatePossibleSubItems();

            DataContext = this;
            CurrentItem = PossibleItems[0];
            CurrentSubitem = PossibleSubitems[0];

            PropertyChanged += (s, o) =>
                {
                    if (o.PropertyName != "CurrentItem") return;
                    UpdatePossibleSubItems();
                    ValidateCurrentSubItem();
                };
        }

        private void ValidateCurrentSubItem()
        {
            if (!PossibleSubitems.Contains(CurrentSubitem))
            {
                CurrentSubitem = PossibleSubitems[0];
            }
        }

        public ObservableCollection<string> PossibleItems
        {
            get { return _possibleItems; }
            private set
            {
                if (Equals(value, _possibleItems)) return;
                _possibleItems = value;
                OnPropertyChanged();
            }
        }

        public ObservableCollection<string> PossibleSubitems
        {
            get { return _possibleSubitems; }
            private set
            {
                if (Equals(value, _possibleSubitems)) return;
                _possibleSubitems = value;
                OnPropertyChanged();
            }
        }

        public string CurrentItem
        {
            get { return _currentItem; }
            private set
            {
                if (value == _currentItem) return;
                _currentItem = value;
                OnPropertyChanged();
            }
        }

        public string CurrentSubitem
        {
            get { return _currentSubitem; }
            set
            {
                if (value == _currentSubitem) return;
                _currentSubitem = value;
                OnPropertyChanged();
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void LoadPossibleItems()
        {
            PossibleItems = new ObservableCollection<string>
                {
                    "Item 1",
                    "Item 2"
                };
        }

        private void UpdatePossibleSubItems()
        {
            if (CurrentItem == PossibleItems[0])
            {
                PossibleSubitems = new ObservableCollection<string>
                    {
                        "Subitem A",
                        "Subitem B"
                    };
            }

            else if (CurrentItem == PossibleItems[1])
            {
                PossibleSubitems = new ObservableCollection<string>
                    {
                        "Subitem B",
                        "Subitem C"
                    };
            }
        }

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

答案 1 :(得分:1)

你正在通知错误的财产。在CurrentItem,您拨打"PossibleSubitems"

private string _currentItem;
public string CurrentItem
{
  get { return _currentItem; }
  set
  {
    _currentItem = value;
    // Changing the item changes the possible sub items
    NotifyPropertyChanged("PossibleSubitems");
  }
}

修复此问题并重试:)


警告......这是一个蠢事...... 我改变它是为了使它工作(只因为我很好奇),但这绝不是正确的方式,也不是优雅的方式:

// List of potential Items, used to populate the options for the Subitems combo box
public ObservableCollection<string> PossibleSubitems { get; set; }

// Track the selected Item
private string _currentItem;
public string CurrentItem
{
    get { return _currentItem; }
    set
    {
        _currentItem = value;
        // Changing the item changes the possible sub items
        if (value == "Item 1")
        PossibleSubitems = new ObservableCollection<string>() {"A","B"} ;
        else
        PossibleSubitems = new ObservableCollection<string>() { "C", "D" };


        RaisePropertyChanged("CurrentItem");
        RaisePropertyChanged("PossibleSubitems");
    }
}

所以基本上,当前项目发生变化时,它会创建新的子项集合...
丑陋 !!!我知道......你可以重复使用这些系列,并做很多其他事情......但正如我所说,我很好奇是否可以这样做......:)

如果这会打破你的键盘,或者你的猫跑掉了,我就不承担任何责任。