【问题标题】:Displaying a selected ComboBox Item in WPF在 WPF 中显示选定的 ComboBox 项
【发布时间】:2015-07-14 22:53:08
【问题描述】:

我正在尝试构建一个显示所选项目的 ComboBox。我可以让组合框很容易地显示选项,但是让选定的项目显示是行不通的。所选项目是指从数据库中提取的值。

我知道 set 方法有效,因为我可以成功存储用户的选择。但是,当我从数据库中抓取它时,我似乎无法让 ComboBox 填充所选项目。

我已经为此沮丧了几个星期,我觉得这个错误很简单。

场景:

我有一个Animal Model

public class AnimalModel
{
    public string AnimalName { get; set; }
    ...
}

每个Animal都有一个AnimalViewModel

public class AnimalViewModel: BindableBase
{
    private AnimalViewModel _animal;

    public AnimalViewModel(AnimalModel animal)
    {
        _animal = animal;
    }

    public string AnimalName
    {
        get { return _animal.Name; }
        set
        {
            if (value != this._animal.Name)
            {
                this._animal.Name = value;
                OnPropertyChanged("AnimalName");
            }
        }
    }
    ...
}

我有一个 ObservableCollectionAnimalViewModel 对象:

public class TemplateViewModel : BindableBase
{
    private ObservableCollection<AnimalViewModel> _animals;
    public TemplateViewModel(...)
    {
        _animal = methodReturnsAnObservableCollectionOfAnimalViewModels();
    }

    public ObservableCollection<AnimalViewModel> Animals
    {
        get { return _animals; }
        set
        {
            if (value != this._animals)
            {
                this._animals = value;
                OnPropertyChanged("Animals");
            }
        }
    }
}

有了这个,我可以轻松地在 ComboBox 中显示AnimalNames 的列表:

<ComboBox ItemsSource="{Binding Animals}" 
          DisplayMemberPath="AnimalName" 
          IsEditable="True" 
          IsReadOnly="True" 
          Text="--- Select Animal ---"/>

我现在绑定到 SelectedItem

public class TemplateViewModel
{
    ...
    private AnimalViewModel _selectedAnimal;
    public TemplateViewModel(MyObject, ...)
    {
        ...
        _selectedAnimal = new AnimalViewModel(new AnimalModel() { AnimalName = MyObject.AnimalName });
    }
    ...
    public AnimalViewModel SelectedAnimal
    {
        get { return _selectedAnimal; }
        set
        {
            if (value != _selectedAnimal)
            {
                _selectedAnimal = value;
                AnimalName = value.AnimalName;
                OnPropertyChanged("SelectedAnimal");
            }
        }
    }
}

所以现在,我有:

<ComboBox ItemsSource="{Binding Animals}" 
          DisplayMemberPath="AnimalName" 
          SelectedItem={Binding SelectedAnimal} 
          SelectedValuePath="AnimalName" 
          IsEditable="True" IsReadOnly="True" 
          Text="--- Select Animal ---"/>

不幸的是,这不会用 Animal 填充 ComboBox。它只是拉出默认选项Select Animal 并填充了选项。它确实正确设置了项目。

任何帮助将不胜感激。

【问题讨论】:

  • 我昨天回答了一个这样的问题here。同样的答案适用:)

标签: c# wpf mvvm


【解决方案1】:

您需要访问相关动物的实际reference

在代码隐藏中,您创建一个 animal,它看起来像 ObservableCollection 中的动物,但它不是 reference 中的动物。

更改(动物加载后

 _selectedAnimal = new AnimalViewModel(...);

to(只使用属性访问器,而不是后备存储变量;所以更改事件会触发,顺便说一句

SelectedAnimal = Animals[0];

测试应用(删除网格行/列等格式)

<Label>SelectedItem</Label>
<TextBlock  Text="{Binding SelectedItem, ElementName=cbMain}"/>
<Label >SelectedValue</Label>
<TextBlock Text="{Binding SelectedValue, ElementName=cbMain}"/>
<Button  Click="ChangeSelectedValue">Set Selected Value</Button>
<ComboBox Name="cbMain"
            ItemsSource="{Binding Ships}"
            SelectedItem="{Binding Ships[0]}"
            SelectedValuePath="Name"
            Text="Select a Ship"/>

屏幕加载结果:

【讨论】:

  • 所以,我完全理解了将reference 传递给对象的逻辑,我觉得没有抓住它很无聊。话虽如此,即使我通过引用传递并初始化属性访问器,我似乎仍然无法获得要显示的选定值。 Set 仍然有效,但我对这个 get 方法感到非常沮丧。
  • 另外,我觉得我还有其他一些概念上的错误。如果我想获取索引,我应该可以做类似_animals.IndexOf(new AnimalViewModel(new AnimalModel { Name = myobject.name })) 但是在集合中找不到对象。我得到-1
  • @Bryant 尝试删除 SelectedValuePath.... 仅当您将所选项目与 SelectedValue 绑定时才应使用,而您不是。
  • @Bryant 至于您的第二条评论,IndexOf 还通过引用比较项目,因此AnimalViewModel 的新实例的引用当然不会存在于_animals 中。你想要像_animals.FirstOrDefault(p =&gt; p.Name == myObject.name) 这样的东西,它转换为“在这个集合中找到.Name 属性等于myObject.name 的第一个项目”
  • @Rachel 我真的不知道我做错了什么。即使没有SelectedValuePath,也不会发生任何事情。我觉得我已经尝试了所有变体。即使设置SelectedAnimal = _animals[0]= Animals[0] 也不起作用。无论我使用支持变量,属性,确保它传递引用。它根本没有设置。
【解决方案2】:

我认为这是SelectedValuePath="AnimalName" 和您的财产之间的命名差异。

public string Animal //<----Should Be AnimalName!
{
    get { return _animal.Name; }
    set
    {
        if (value != this._animal.Name)
        {
            this._animal.Name = value;
            OnPropertyChanged("AnimalName");
        }
    }
}

将您的属性更改为 AnimalName,您就可以开始了。

【讨论】:

  • 对不起,这是我在 SO 中输入的一个错字。还是没有运气。
猜你喜欢
  • 2016-03-12
  • 1970-01-01
  • 2021-03-11
  • 2020-10-10
  • 2014-11-05
  • 1970-01-01
  • 2011-04-19
  • 2020-12-11
  • 1970-01-01
相关资源
最近更新 更多