2016-05-05 67 views
0

我有一个组合框绑定到对象的集合。这些对象具有属性布尔值IsSelected,该属性指定当前是否选择要在ComboBox文本区域中显示的对象。组合框,WPF非常新

为了使它使用IsSelected布尔属性来显示ComboBox中的默认项目,我添加了一个类似下面的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; 
     } 
    } 

我ComboBox位于UserContrl及其XAML是:

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

我使用的SelectedItem,因为我的车对象有IsSelected是布尔和它所代表的汽车是否在组合框的文本区域中可见, 。出于这个原因,我有上面的ValueConverter使用该布尔值来正确返回对象。

这很好,当ComboBox加载时,IsSelected = True的对象将显示在ComboBox文本区域中。但是,如果我展开下拉菜单并选择另一个对象,则该对象将显示,但ComboBox会获得一个红色边框,据我所知,这意味着存在一些验证问题。

我该如何解决这个问题?

我见过很多例子,但他们都没有解决布尔属性IsSelected用来确定在ComboBox中显示哪个对象的问题。

我该如何解决这个问题?

+1

也许问题是'ConvertBack'功能,它应该返回'IEnumerable的 CarsList'。无论如何,我认为你应该用这种方式重新考虑对'SelectedItem'的绑定。 – bars222

+0

你是对的,ConvertBack正在返回Car实例而不是CarList实例。但问题是我没有CarList实例,因为它没有传递到ConvertBack。所以不知道如何让它返回。 – pixel

+1

我认为@Bolu建议如何更改绑定的好方法。否则,您可以尝试将'CarList'作为'ConverterParameter'传递(如果'CarList'集合永远不会更改,您可以在xaml中像定义资源那样定义它),但这是奇怪复杂的方式。 – bars222

回答

1

在WPF中,使用ComboBox的一个常见的做法是如下:

在视图模型

  • 定义集合在你的虚拟机属性(如你为 CarsList
  • 将选定项目定义为虚拟机中的一个属性(使用 其他属性,例如:SelectedCar

在查看

  • 绑定ItemsSource到 '收集' 属性。
  • 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> 

结果:TextBlock文本将更新时选择的ComboBox改变。

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更新所选项目 - 但您应该通过将combox的SelectedItem直接绑定到公共SelectedCar属性在ViewModel上。加载视图模型时,您可以通过检查列表来初始化此SelectedCar,并将相应的项目显示为选中状态。

+0

我想弄清楚为什么转换器不能返回正确的值。谢谢安德鲁。 – pixel

-1

您似乎想将MVVM模式应用于您的设计。 我建议你不需要转换器,你可以在你的视图模型中管理你的集合。