0

2 つのコンボ ボックスがあります。1 つは「アイテム」のリストを含み、もう 1 つは「サブアイテム」のリストを含みます。

サブアイテムのリストは、現在選択されているアイテムによって異なります。

この作業のほとんどは (Subitems の ItemSource を PossibleSubitems プロパティにバインドすることによって) 行っていますが、問題は、Item を変更すると Subitem が新しいアイテムに対して有効でなくなることです。この場合、最初の有効なサブアイテムを選択したいだけですが、代わりに空のコンボ ボックスが表示されます。クラスのプロパティは正しく設定されていると思いますが、バインディングはそれを正しく反映していないようです。

ここに私が何をしているのかを示すコードがあります。この場合、サブアイテム A またはサブアイテム B を持つことができる「アイテム 1」と、サブアイテム B またはサブアイテム C を持つことができる「アイテム 2」があります。

サブアイテム 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");
    }
}

基本的に、現在のアイテムが変更されると、サブアイテムの新しいコレクションが作成されます...
醜い!!! 私は知っています...あなたはそれらのコレクションを再利用し、他の多くのことを行うことができます...しかし、私が言ったように、私はそれがこの方法でできるかどうかに興味がありました... :)

これによりキーボードが壊れたり、猫が逃げたりしても、私は一切責任を負いません。

于 2013-11-14T10:45:07.080 に答える