ComboBox中的选定属性未显示

时间:2015-06-06 13:50:36

标签: c# wpf xaml mvvm

我有一个ViewModel,它有一个集合和一个属性,表示集合中的选定值。在我看来,这是在ComboBox中显示的。当“填充”我的ViewModel时,我的视图中不会显示所选项目。

我的ViewModel

public class DriverViewModel : MasterDataWithAddressViewModel<Driver>
{
    public ObservableCollection<Vehicle> Vehicles
    {
        get { return _vehicles; }
        set
        {
            if (_vehicles != value)
            {
                _vehicles = value;
                RaisePropertyChanged("Vehicles");
            }
        }
    }
    public Vehicle SelectedVehicle
    {
        get { return PrimaryModel.Vehicle; }
        set
        {
            if (PrimaryModel.Vehicle != value)
            {
                PrimaryModel.Vehicle = value;
                RaisePropertyChanged("SelectedVehicle");
            }
        }
    }
}

正确调用SelectedVehicle的setter,RaisePropertyChanged("SelectedVehicle"); ...

也是如此

我的ComboBox

<ComboBox DisplayMemberPath="Number" 
          ItemsSource="{Binding Vehicles, UpdateSourceTrigger=PropertyChanged}" 
          SelectedValue="{Binding SelectedVehicle, UpdateSourceTrigger=PropertyChanged}" />

我也是这样试过的:

<ComboBox DisplayMemberPath="Number" 
           ItemsSource="{Binding Vehicles, UpdateSourceTrigger=PropertyChanged}" 
           SelectedItem="{Binding SelectedVehicle, UpdateSourceTrigger=PropertyChanged}" 
            IsSynchronizedWithCurrentItem="True" />

在“手动”(通过视图)中选择ComboBox中的值可以正常工作。通过在代码中“填充”ViewModel来实现它不起作用。

有人可以帮忙吗?

3 个答案:

答案 0 :(得分:3)

因为您的媒体资源SelectedVehicle是参考类型 将SelectedValue绑定到ViewModel.SelectedVehicle时 组合框将有界Collection的对象与SelectedVehicle

的对象进行比较

通过调用.Equals方法进行比较,默认情况下比较引用并在两个对象引用相同内存地址时返回true

由于未显示所选项目,因此我假设SelectedVehicle的参考不在集合Vehicles中。

您可以覆盖类Equals中的Vehicle方法,以便按某些属性进行比较。在你的情况下,这将是最短的方式 通过SelectedItem使用您的第二种方法,并在Equals类中覆盖Vehicle方法:

public override bool Equals(Person compareTo)
{
    if (compareTo == null)
        return false;
    return (this.ID == compareTo.ID);
}

或者我更喜欢下一个方法 使用标识Vehicle ValueMemberPath

的属性
<ComboBox DisplayMemberPath="Number" 
      ValueMemberPath="Number"
      ItemsSource="{Binding Vehicles, UpdateSourceTrigger=PropertyChanged}" 
      SelectedValue="{Binding SelectedVehicle, UpdateSourceTrigger=PropertyChanged}" />

在ViewModel中

public Int32 SelectedVehicleNumber
{
    get { return PrimaryModel.Vehicle.Number; }
    set
    {
        if (PrimaryModel.Vehicle.Number != value)
        {
            PrimaryModel.Vehicle = New Vehicle(value);//Create instance by selected value
            RaisePropertyChanged("SelectedVehicle");
        }
    }
}

使用KeyedCollection

的另一种方法

答案 1 :(得分:1)

尝试绑定SelectedItem而不是SelectedValue

此外,请确保在 Vehicles属性之前设置了SelectedVehicle属性。

答案 2 :(得分:0)

我在这方面做了一个小例子:

我有这个简单的观点:

<Window x:Class="ComboSelectedItemBinding.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:ComboSelectedItemBinding"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <Grid.DataContext>
        <local:ViewModel/>
    </Grid.DataContext>
    <StackPanel>
        <ComboBox ItemsSource="{Binding vehicles, UpdateSourceTrigger=PropertyChanged}" SelectedItem="{Binding VehicleSelected}" DisplayMemberPath="Name" SelectedIndex="0" VerticalAlignment="Top"/>
        <TextBox x:Name="VehName" MinWidth="120" Margin="80,10" />
        <Button Content="Change selection" Command="{Binding ChangeCommand}" CommandParameter="{Binding ElementName=VehName, Path=Text}" Margin="10" Width="150"/>
    </StackPanel>

</Grid>

这是模型:

public class Vehicle : INotifyPropertyChanged
{
    private string _Name;

    public string Name
    {
        get { return _Name; }
        set { _Name = value; }
    }


    public event PropertyChangedEventHandler PropertyChanged = delegate { };

    public void OnPropertyChanged(string propertyName)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName ));
    }
}

ViewModel:

public class ViewModel : DependencyObject
{
    public ObservableCollection<Vehicle> vehicles { get; set; }

    public ICommand ChangeCommand { get; set; }


    public Vehicle VehicleSelected
    {
        get { return (Vehicle)GetValue(VehicleSelectedProperty); }
        set { SetValue(VehicleSelectedProperty, value); }
    }

    // Using a DependencyProperty as the backing store for VehicleSelected.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty VehicleSelectedProperty =
        DependencyProperty.Register("VehicleSelected", typeof(Vehicle), typeof(ViewModel), new PropertyMetadata(null));



    public ViewModel()
    {
        vehicles = new ObservableCollection<Vehicle>();
        Vehicle veh1 = new Vehicle() { Name = "V1" };
        Vehicle veh2 = new Vehicle() { Name = "V2" };
        Vehicle veh3 = new Vehicle() { Name = "V3" };
        Vehicle veh4 = new Vehicle() { Name = "V4" };

        vehicles.Add(veh1);
        vehicles.Add(veh2);
        vehicles.Add(veh3);
        vehicles.Add(veh4);

        ChangeCommand = new ChangeCommand(this);
    }
}

按钮的命令:

    public class ChangeCommand : ICommand
{
    public ViewModel _vm = null;

    public ChangeCommand(ViewModel vm)
    {
        _vm = vm;
    }
    public bool CanExecute(object parameter)
    {
        return true;
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
       _vm.VehicleSelected = _vm.vehicles.First( name => name.Name.Equals(parameter.ToString()));
    }
}

为了在组合框中进行更改,您必须保留对其有界集合中的一个对象的引用。为了实现这一点,我已经添加了根据车辆名称更改选择的方法。使用车辆名称,您可以搜索列表中的引用项目,并将其设置为SelectedItem,它被定义为DependencyProperty,只是为了做一个小的变化。