未显示组合框中选定的属性

本文关键字:属性 显示 组合 | 更新日期: 2023-09-27 17:53:59

我有一个ViewModel,它有一个集合和一个表示集合中所选值的属性。在我看来,这是显示在一个组合框。当"填充"我的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 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" />

在组合框中"手动"选择一个值(通过视图)没有问题。在代码中"填充"ViewModel是行不通的。

有谁能帮忙吗?

未显示组合框中选定的属性

因为你的属性SelectedVehicle是引用类型
当你将SelectedValue绑定到ViewModel.SelectedVehicle
combobox比较有界集合的对象和SelectedVehicle的对象

通过调用.Equals方法进行比较,该方法默认比较引用,如果两个对象引用相同的内存地址,则返回true

因为所选项目没有显示,我假设SelectedVehicle的引用不在集合Vehicles中。

您可以在Vehicle类中重写Equals方法以通过某些属性进行比较。对你来说,这是最快捷的方法。
SelectedItem中使用第二种方法,并在Vehicle类中重写Equals方法:

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

或者我更喜欢next方法more
使用识别ValueMemberPath车辆的属性

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

In 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

尝试绑定SelectedItem而不是SelectedValue

另外,确保Vehicles属性设置在 SelectedVehicle属性之前

我做了一个小例子:

我有这个简单的视图:

<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, SelectedItem被定义为DependencyProperty,只是为了做一个小小的改变。