2016-05-05 13 views
0

私はオブジェクトのコレクションにバインドされたComboBoxを持っています。オブジェクトには、オブジェクトが現在コンボボックステキスト領域に表示されるように選択されているかどうかを指定するプロパティboolean IsSelectedがあります。ComboBox、WPFの新機能

ComboBoxにデフォルトのアイテムを表示するためにIsSelectedブール値プロパティを使用するために、以下のようなValueConverterクラスを追加しました。

public class SelectedItemConverter : IValueConverter 
    { 

     public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
     { 
      if (value != null && value is IEnumerable<Car>) 
      { 
       return ((IEnumerable<Car>)value).Where(n => n.IsSelected).FirstOrDefault(); 
      } 
      return null; 
     } 

     public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
     { 
      if (value != null && value is Car) 
      { 
       return value; 
      } 
      return null; 
     } 
    } 

私のコンボボックスはUserContrlであり、そのXAMLは次のとおりです。私の車のオブジェクトがブール値であるIsSelectedを持っており、それは車がコンボボックスのテキスト領域に表示されているかどうかを表しているので、私はのSelectedItemを使用しています

<ComboBox ItemsSource="{Binding CarsList}" 
      SelectedItem="{Binding CarsList, Converter={StaticResource selectedItemConverter}}" 
      DisplayMemberPath="Name"> 
</ComboBox> 

。そのため、上記のValueConverterを使用してオブジェクトを適切に返すようにします。

これは正常に動作し、ComboBoxが読み込まれると、IsSelected = Trueのオブジェクトがコンボボックスのテキスト領域に表示されます。しかし、ドロップダウンを展開して別のオブジェクトを選択すると、そのオブジェクトが表示されますが、ComboBoxは赤枠線を取得します。これは私が知る限り、いくつかの検証の問題があることを意味します。

これを修正するにはどうすればよいですか?

私は多くの例を見てきましたが、ブール型プロパティIsSelectedを使用してComboBoxに表示するオブジェクトを決定する問題は解決していません。

どうすれば解決できますか?

+1

おそらく問題は 'ConvertBack'機能である、それは' IEnumerableを CarsList'を返す必要があります。とにかく、あなたはその方法で 'SelectedItem'への束縛を再考するべきだと思います。 – bars222

+0

あなたは正しい、ConvertBackはCarインスタンスを返していて、CarListインスタンスは返していません。しかし、問題は、ConvertBackに渡されないCarListインスタンスがないことです。どのようにそれを返すようにするか分からない。 – pixel

+1

私は@Boluがバインディングを変更する良い方法を提案したと思います。そうでなければ 'CarList'を' ConverterParameter'として渡すことができます(もし 'CarList'コレクションが決してあなたがリソースのようなxamlでそれを定義することができます)が、これは奇妙な複雑な方法です。 – bars222

答えて

1

ComboBoxを使用する一般的な方法は以下の通りです:ViewModelに

  • (あなたが CarsListために行ったように)あなたのVMにおけるプロパティとしてコレクションを定義
  • 選択した項目をVM内のプロパティとして定義します( 別のプロパティを使用します。: 'コレクション' プロパティに表示

    • バインドItemsSourceSelectedCar

  • バインドSelectedItemを 'selected item'プロパティにバインドします。

<ComboBox ItemsSource="{Binding CarsList}" 
      SelectedItem="{Binding SelectedCar}" 
      DisplayMemberPath="Name"> 
</ComboBox> 

あなたが選択のためのデフォルトの項目を設定したい場合は、単にその項目にSelectedCarプロパティを設定します。ユーザーが選択を変更したときには、常にSelectedCarプロパティから選択項目を取得することができます。

編集:簡単な作業例:

のC#:

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

namespace WpfApplication1 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 
      MyViewModel mvm = new MyViewModel() 
      { 
       CarsList = new ObservableCollection<Car>() 
       { 
        new Car() { Name = "Car1" }, 
        new Car() { Name = "Car2" }, 
        new Car() { Name = "Car3" }, 
        new Car() { Name = "Car4" } 
       } 
      }; 
      this.DataContext = mvm; 
     } 
    } 

    public class MyViewModel : ObservableObject 
    { 
     private Car _selectedcar; 
     public ObservableCollection<Car> CarsList 
     { 
      get; 
      set; 
     } 

     public Car SelectedCar 
     { 
      get { return _selectedcar; } 
      set 
      { 
       if (value != _selectedcar) 
       { 
        _selectedcar = value; 
        RaisePropertyChanged("SelectedCar"); 
       } 
      } 
     } 


    } 

    public class Car : ObservableObject 
    { 
     private string _name; 
     public string Name 
     { 
      get { return _name; } 
      set 
      { 
       if (value != _name) 
       { 
        _name = value; 
        RaisePropertyChanged("Name"); 
       } 
      } 
     } 
    } 

    public class ObservableObject : INotifyPropertyChanged 
    { 
     public event PropertyChangedEventHandler PropertyChanged; 

     protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) 
     { 
      var handler = this.PropertyChanged; 
      if (handler != null) 
      {     
       handler(this, e); 
      } 
     } 

     protected void RaisePropertyChanged(String propertyName) 
     { 
      OnPropertyChanged(new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 

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="300" Width="300"> 
    <StackPanel Orientation="Vertical"> 
     <ComboBox ItemsSource="{Binding CarsList}" 
      SelectedItem="{Binding SelectedCar}" 
      DisplayMemberPath="Name"> 
     </ComboBox> 
     <TextBlock Text="{Binding SelectedCar.Name}"/> 
    </StackPanel> 
</Window> 

結果:ComboBoxの選択が変更されたときTextBlockのテキストが更新されます。

Text in TextBlock updated when user select from ComboBox

+0

もう少し詳しく説明していただけますか?このようにComboBoxの良い例がありますか?大いに感謝しています – pixel

+0

非常に高く評価されたBolu。それは非常に役に立ちます。 – pixel

1

ComboBoxのSelectionChangedイベントを使用して、バインドされたリストの各アイテムのIsSelectedプロパティを更新し、新しい選択のみを 'True'に設定し、その他はすべて「False」に設定します。

これは、@ bars222が現在バインドしている列挙型の型を正しく返していないと指摘しているコンバーターは必要ありません。

アイテムの 'IsSelected'プロパティを 'True'に設定したときにコンボボックスが選択したアイテムを更新することはできませんが、ComboBoxのSelectedItemを公開SelectedCarプロパティに直接バインドして変更する必要がありますViewModelでビューモデルがロードされると、リストを調べることによってこのSelectedCarを初期化することができ、適切な項目が選択されたものとして表示されます。

+0

私は、コンバータが適切な値を返さない理由を把握しようとしています。 Andrewに感謝します。 – pixel

-1

デザインにMVVMパターンを適用すると思われます。 私はコンバータが必要ないことをお勧めします、ビューモデルであなたのコレクションを管理することができます。 WPFでは