2016-09-06 255 views
0

オブジェクトを切り替えるコンボボックスを作成しようとしています。一般的な要点は、オブジェクトにはComboBoxに表示されるKeyと、理論上は何でもできるDataコンポーネントがあることです。データコンポーネントは複雑で、キーは単なる文字列です。下の例では、Dataは単なるUriですが、実際にはデータのタイプは問題ではありません。Combobox SelectedItemがNULLになる

基本的な目的は、ComboBoxのSelectedItemをモデルにバインドして、SelectedItemのデータを他の相互作用を通じて変更できるようにすることです。

コードは、いくつかの項目がComboBoxに追加され、SelectedItemが最初の要素として選択されるように設定されています。それはうまく動作します。私がボタンをクリックすると、SelectedItemは例外をスローするところでnullに割り当てられます。

なぜSelectedItemはnullに割り当てられますか?

ここに完全な作業コードです。私の目標は.NET 4.0ですが、それはそれほど重要ではないと推測しています。 XAMLは次のとおりです。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Data; 
using System.Windows.Documents; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Imaging; 
using System.Windows.Navigation; 
using System.Windows.Shapes; 
using System.ComponentModel; 
using System.Collections.ObjectModel; 
using System.Collections.Specialized; 

namespace Sandbox 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     public Model Model { get; set; } 

     public MainWindow() 
     { 
      InitializeComponent(); 
      this.DataContext = this; 

      Model = new Model(); 

      this.Model.Items.Add(
       new ObservableKeyValuePair<string, Uri>() 
       { 
        Key = "Apple", 
        Value = new Uri("http://apple.com") 
       }); 

      this.Model.Items.Add(
       new ObservableKeyValuePair<string, Uri>() 
       { 
        Key = "Banana", 
        Value = new Uri("http://Banana.net") 
       }); 

      this.Model.SelectedItem = this.Model.Items.First(); 
     } 

     private void Button_Click(object sender, RoutedEventArgs e) 
     { 
      this.Model.SelectedItem.Value = new Uri("http://cranberry.com"); 
     } 
    } 

    public class TrulyObservableCollection<T> : ObservableCollection<T> where T : INotifyPropertyChanged 
    { 
     public TrulyObservableCollection() 
     { 
      CollectionChanged += FullObservableCollectionCollectionChanged; 
     } 

     public TrulyObservableCollection(IEnumerable<T> pItems) 
      : this() 
     { 
      foreach (var item in pItems) 
      { 
       this.Add(item); 
      } 
     } 

     private void FullObservableCollectionCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) 
     { 
      if (e.NewItems != null) 
      { 
       foreach (Object item in e.NewItems) 
       { 
        ((INotifyPropertyChanged)item).PropertyChanged += ItemPropertyChanged; 
       } 
      } 
      if (e.OldItems != null) 
      { 
       foreach (Object item in e.OldItems) 
       { 
        ((INotifyPropertyChanged)item).PropertyChanged -= ItemPropertyChanged; 
       } 
      } 
     } 

     private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e) 
     { 
      NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, sender, sender, IndexOf((T)sender)); 
      OnCollectionChanged(args); 
     } 
    } 

    public class ObservableKeyValuePair<TKey, TValue> : 
     INotifyPropertyChanged, 
     IEquatable<ObservableKeyValuePair<TKey, TValue>> 
    { 
     public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; 

     protected virtual void OnPropertyChanged(string propertyName) 
     { 
      if (PropertyChanged != null) 
      { 
       PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); 
      } 
     } 

     public override bool Equals(object rhs) 
     { 
      var obj = rhs as ObservableKeyValuePair<TKey, TValue>; 

      if (obj != null) 
      { 
       return this.Key.Equals(obj.Key); 
      } 

      return false; 
     } 

     public bool Equals(ObservableKeyValuePair<TKey, TValue> other) 
     { 
      return this.Key.Equals(other.Key); 
     } 

     public override int GetHashCode() 
     { 
      return this.Key.GetHashCode(); 
     } 

     protected TKey _Key; 
     public TKey Key 
     { 
      get 
      { 
       return _Key; 
      } 
      set 
      { 
       if (value is INotifyPropertyChanged) 
       { 
        (value as INotifyPropertyChanged).PropertyChanged += new PropertyChangedEventHandler(KeyChanged); 
       } 

       _Key = value; 

       OnPropertyChanged("Key"); 
      } 
     } 
     void KeyChanged(object sender, PropertyChangedEventArgs e) 
     { 
      OnPropertyChanged("Key"); 
     } 

     protected TValue _Value; 
     public TValue Value 
     { 
      get 
      { 
       return _Value; 
      } 
      set 
      { 
       if (value is INotifyPropertyChanged) 
       { 
        (value as INotifyPropertyChanged).PropertyChanged += new PropertyChangedEventHandler(ValueChanged); 
       } 

       _Value = value; 

       OnPropertyChanged("Value"); 
      } 
     } 
     void ValueChanged(object sender, PropertyChangedEventArgs e) 
     { 
      OnPropertyChanged("Value"); 
     } 
    } 

    public class Model : INotifyPropertyChanged 
    { 
     public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; 

     public Model() 
     { 
      Items = new TrulyObservableCollection<ObservableKeyValuePair<string, Uri>>(); 
     } 

     protected virtual void OnPropertyChanged(string propertyName) 
     { 
      if (PropertyChanged != null) 
      { 
       PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); 
      } 
     } 

     public TrulyObservableCollection<ObservableKeyValuePair<string, Uri>> Items { get; set; } 
     public ObservableKeyValuePair<string, Uri> _SelectedItem = null; 
     public ObservableKeyValuePair<string, Uri> SelectedItem 
     { 
      get 
      { 
       return Items.FirstOrDefault(x => _SelectedItem != null && x.Key == _SelectedItem.Key); 
      } 
      set 
      { 
       if (value == null) 
       { 
        throw new Exception("This is the problem"); 
       } 

       if (_SelectedItem != value) 
       { 
        _SelectedItem = value; 
        OnPropertyChanged("SelectedItem"); 
       } 
      } 
     } 
    } 
} 

XAML:私は合計でよ

<Window x:Class="Sandbox.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525"> 
    <StackPanel> 
     <Button Click="Button_Click" Content="Clsick Me"/> 
     <ComboBox IsEditable="False" ItemsSource="{Binding Model.Items}" SelectedItem="{Binding Model.SelectedItem, Mode=TwoWay}"> 
      <ComboBox.ItemTemplate> 
       <DataTemplate> 
        <TextBlock Text="{Binding Key}"> 
        </TextBlock> 
       </DataTemplate> 
      </ComboBox.ItemTemplate> 
     </ComboBox> 
    </StackPanel> 
</Window> 

は "値が" nullである理由を説明しようとして失います。あなたは根本的な問題がSelector.OnItemsChangedの実装であるコレクション

+0

ボタンクリックで何をしますか? 'SelectedItem'を別のものに変更するか、現在の' SelectedItem'の 'value'プロパティを変更しますか? – Gopichandar

+0

@Gopichandar SelectedItemのプロパティを変更したいと思います。この例では、propertyはValueです。私はEqualsが使用するプロパティを変更していません。 –

答えて

0

ではありません選択した項目の値を代入しようとしているため

0

値はnullになります。メソッドの終わりに向かって、現在SelectedItemがNULLになります。

私はOnItemsChangedをオーバーライドする新しいComboBoxクラスを派生させることによってこの問題を回避働いていた、現在のSelectedItemを保存し、base.OnItemsChangedを呼び出し、SelectedItemをリセットします。これは、SelectedItemのvalid => null => validからの遷移が望ましくない場合、モデルに "InhibitEvents"フラグを伝播させる必要があります。

+0

SelectedItemはすでにコレクションにあります。既存のSelectedItemのプロパティを変更しようとしています。値はEquals()ロジックでも使用されません。 –

関連する問題