2013-11-14 2 views
0

У меня есть 2 поля со списком, в которых содержится список «Элементы» и другой, который содержит список «Подэлементы».Как связать два комбинированных поля вместе в wpf

Список подэлементов зависит от выбранного в данный момент элемента.

У меня есть большая часть этой работы (связывая ItemSource подэлементов с свойством PossibleSubitems), однако проблема заключается в том, что я изменяю Item и Subitem больше не действует для нового элемента. В этом случае я просто хочу выбрать первый действительный подпункт, но вместо этого получаю пустой комбинированный ящик. Обратите внимание, что я считаю, что свойство в классе задано правильно, но привязка, похоже, не отражает его правильно.

Вот какой код, чтобы показать вам, что я делаю. В этом случае, у меня есть: «Пункт 1», который может иметь подпозиция A или подпозиция B и «Пункт 2», который может иметь подпозиция B или подпозиция C

Проблема возникает при переходе к пункту 2, когда у меня есть Выбран подпункт A.

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

    } 
} 

ответ

1

я переписал свой собственный образец - держали его код позади, чтобы не отклоняться от вашего образца слишком много. Кроме того, я использую .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)); 
     } 
    } 
} 
+0

Согласен с другими плакатами комментарии относительно принятия подхода MVVM. Ключевым моментом здесь является то, что вам нужно моделировать коверцию явно, а не взламывать ее. –

+0

Я не уверен на 100%, что ему нужно, если он сделает это правильно ... Я уверен, что INPC позаботится об этом ... – Noctis

+0

Вы можете сделать это с помощью INPC, но он неэффективен и может взорваться один раз с более сложными моделями, где важны проблемы. В прошлом я привязывался в узлах, не делая этого явно. Я думаю, что лучше быть откровенным с самого начала. YMMV ... –

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

Fix, что и попробуйте еще раз :)


ВНИМАНИЕ ... ЭТО HACK ... я это, чтобы сделать его работу изменилось (только потому, что мне было интересно), но это, не означает, что собственно образом, ни один элегантный:

// 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 !!! Я знаю ... Вы можете повторно использовать эти коллекции и делать много других вещей ... но, как я уже сказал, мне было любопытно, можно ли это сделать ... :)

Если это сломает ваш клавиатура, или ваша кошка убегает, я НЕ ОТВЕТСТВЕННОСТЬЮ НЕ ОТВЕТСТВЕННОСТЬ.

+0

Но когда я меняю элемент, это возможные подпункты, которые меняются (я должен, вероятно, уведомить об изменении CurrentItem). Если я не уведомляю о возможностях, то поле SubItems не обновляется вообще и показывает совершенно неправильное значение, а не пусто – steeveeet

+1

Ну ... вы изменили CurrentItem ... вещь, я скорее недоволен вашей реализацией ... Я бы пошел с некоторым MVVM (не кодом позади) и имел 2 разных списка подэлементов (вы все равно можете это сделать). Соблюдайте привязку подтитов к правильному, и когда вы измените свой CurrentItem, вы можете сделать что-то вроде «Возможные элементы = this_or_that_collection». Тогда это изменится, и свойство INPC будет срабатывать и в этом случае, и gui изменит – Noctis

+0

+1 для комментария MVVM –

Смежные вопросы