【问题标题】:How to select an instance of object from ComboBox that filled by objects如何从由对象填充的 ComboBox 中选择对象实例
【发布时间】:2021-05-26 18:51:55
【问题描述】:

这个问题可能很愚蠢,但我是 WPF 的新手,所以我很抱歉。 我在这里发现了很多类似的问题,但都没有帮助。

我有一个表单,它获取一些带有Location 属性的对象作为输入。 我希望在显示表单时在ComboBox 中选择此Location 属性。 我还想让这个属性在表单的生命周期中可变。

我是这样绑定的:

<ComboBox Name="CB_Location" ItemsSource="{Binding Locations}" SelectedItem="{Binding SelectedLocation}" DisplayMemberPath="LocationName" SelectedValuePath="LocationID" SelectionChanged="CB_Location_SelectionChanged"/>
public class Location
{
    public int LocationID { get; set; }
    public string LocationName { get; set; }
}
public Form(object _obj)
{
    InitializeComponent();

    lctrl = new LocationController();
    Locations = lctrl.GetAllLocations();

    SelectedLocation = lctrl.GetLocationById(_obj.LocationID);

    DataContext = this;    
}

public List<Location> Locations { get; set; }
public Location SelectedLocation; { get; set; }

ComboBox 已正确填充对象,但我无法正确设置 SelectedItem 属性。

【问题讨论】:

  • 为什么不使用SelectedValue设置SelectedValuePath?什么是选定位置?如果它是当前 DataContext 中 Location 类型的属性,请确保它的值是 Location 对象,它是 Locations 集合的成员。否则转成int类型的属性,绑定SelectedValue而不是SelectedItem,设置成SelectedLocation = _obj.LocationID;
  • 是的,SelectedLocation 是 Location 类型的属性。 Locations 集合包含所有可能的位置,包括 SelectedLocation。
  • public Location SelectedLocation; 是一个字段,而不是一个属性。
  • @Clemens 修复了这个问题。谢谢你。但是还是不行。

标签: c# .net wpf xaml data-binding


【解决方案1】:

未设置选中项的问题是因为SelectedLocation是一个字段,不能绑定。更多关于绑定源的信息,可以参考documentation

您可以绑定到任何公共语言运行时 (CLR) 对象的公共属性、子属性以及索引器。绑定引擎使用 CLR 反射来获取属性的值。或者,实现 ICustomTypeDescriptor 或注册了 TypeDescriptionProvider 的对象也可以与绑定引擎一起使用。

为了使您当前的代码正常工作,只需将 SelectedLocation 设为公共属性。

public Location SelectedLocation { get; set; }

除此之外,如果只想绑定选中的项,设置SelectedValuePath是没用的。

<ComboBox Name="CB_Location"
          ItemsSource="{Binding Locations}"
          SelectedItem="{Binding SelectedLocation}"
          DisplayMemberPath="LocationName"
          SelectionChanged="CB_Location_SelectionChanged"/>

如果您想在 SelectedValuePath 适用的地方绑定 SelectedValue,则必须公开与所选值路径类型匹配的属性,此处为 int

public int SelectedLocationID { get; set; }

然后您可以将SelectedValue 与值路径LocationID 绑定(不带SelectedItem)。

<ComboBox Name="CB_Location"
          ItemsSource="{Binding Locations}"
          DisplayMemberPath="LocationName"
          SelectedValuePath="LocationID"
          SelectedValue="{Binding SelectedLocationID}"
          SelectionChanged="CB_Location_SelectionChanged"/>

关于更新属性的另一个说明。看来您没有实现INotifyPropertyChanged 接口。例如,如果您设置Location,用户界面(此处为ComboBox)将不会反映更改,因为它不会收到通知。因此,如果您打算更改表单中绑定的Location或其他属性,则必须implement INotifyPropertyChanged,例如:

public class YourViewModel : INotifyPropertyChanged
{
   private Location _selectedLocation;
   public Location SelectedLocation
   {
      get => _selectedLocation;
      set
      {
         if (_selectedLocation == value)
            return;
   
         _selectedLocation = value;
         OnPropertyChanged();
      }
   }

   protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
   {
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
   }

   // ...other code.
}

【讨论】:

  • 谢谢@thatguy。我已经将 SelectedLocation 设为公共财产。但 SelectedLocation 仍未正确应用于组合框。
  • 这很奇怪,但似乎 SelectedLocationID 成功了。现在 ComboBox 显示 Value 并且 SelectionChanged 正在工作。我现在很感兴趣,哪种方式更正确:保持原样或继续尝试使用 ObservableCollection 之类的东西。
  • @PavelPolushin 这应该与ObservableCollection&lt;T&gt; 无关。只有在运行时修改集合时才需要它。如果你在构造函数中创建一个集合并且从不修改它,你就不需要它,一个简单的列表就足够了(或只读集合)。这两种方法都应该可以正常工作,因为GetLocationById 返回 Locations 中存在的项目的 same 实例,如 mm8 在另一个答案中所示。两者都是正确,这取决于您的用例更适合。 不要在 XAML 中混合使用这两种方法(意外结果),这一点很重要。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多