0

我有 2 个组合框,一个包含“项目”列表,另一个包含“子项目”列表。

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

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

这是一些代码,可以向您展示我在做什么。在这种情况下,我有:“项目 1”可以有子项目 A 或子项目 B,“项目 2”可以有子项目 B 或子项目 C

当我选择了子项 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));
      }
    }

  }
}
4

2 回答 2

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));
        }
    }
}
于 2013-11-14T10:44:15.490 回答
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");
    }
}

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

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

于 2013-11-14T10:45:07.080 回答