奇怪的问题绑定到ComboBox,其中显示值有时显示为空白

时间:2010-07-02 17:32:32

标签: wpf data-binding combobox

我在绑定到ComboBox时遇到一个奇怪的问题,其中显示值有时会显示为空白。然而,该案例是可重复的,并且第二次从另一个父表单打开一个对话框时发生。如果父窗体关闭并重新打开,则第一次打开它的子​​对话框时,包含的WPF ComboBox会正确显示显示属性。如果我然后关闭对话框并从同一父表单重新启动它,则ComboBox不显示任何显示值,即使我可以验证在我的ViewModel中正在命中相同的绑定属性。

<ComboBox ItemsSource="{Binding AvailableVehicles}"
          SelectedValuePath="Value"
          SelectedValue="{Binding SelectedVehicle, Mode=TwoWay}"
          DisplayValuePath="Value.Model" />

为了解释我的ViewModel的数据结构,它基本上只是一个公开AvailableVehicles集合的类,它包含一个类似于Nullable&lt;&gt;的对象。输入它包装一个Vehicle对象并通过Value属性公开它。然后每辆车都有一个模型和成本属性。

我现在一直在对这个问题进行故障排除超过一天,我几乎排除了一切,但这是ComboBox本身的一个错误。所以在这一点上我希望有一个合理的解决方法,但如果有人能够帮助指出我的代码中的一个缺陷也会很棒。

注意:

  • 我无法在更简单的单个Window WPF示例中重现此问题。
  • WinForms互操作方案,其中我有一个MDI父表单和包含WPF UserControls的子表单,以防可能相关。
  • 如果我在ItemsSource或SelectedValue绑定上将IsAsync设置为True,则问题不再出现。
  • 如果我将DisplayValuePath改为ItemsTemplate并且在定义的DataTemplate中的绑定中放置转换器,我注意到传入的值是null而不是预期的值。

3 个答案:

答案 0 :(得分:2)

我遇到了同样的问题,只有我发现的解决方案是在我的ViewModel中创建两个属性。一个作为选定值(Value),但它不绑定到ComboBox,一个绑定到SelectedItem绑定(SelectedItem)。在SelectedItem getter中,我返回Values.FirstOrDefault(x =&gt; x.Value == Value),在setter中我按Value.Value设置Value。最后,当在OnValueChanged属性中更改了值时,我通知View有关SelectedItem的更改(NotifyPropertyChanged(“SelectedItem”))...

答案 1 :(得分:2)

我认为问题与绑定到SelectedValue的对象有关,并且绑定到ItemsSource的对象本质上是相同数据的不同实例,恰好是没有覆盖Equals的类的实例或者==运算符等。根据我现在经历过的几次,自从SelectedValue或者在某些情况下,SelectedItem在技术上并不等同于绑定的ItemsSource中的任何对象,那么它将被忽略,并且您将获得UI中显示的空白值。 / p>

在这种特殊情况下的问题很可能是我在表单关闭时重用了所选的值,但是每次打开对话框时都可能重新生成锁定列表。

因此,当我在任何代码中看到此症状时,我现在要检查的第一件事是绑定的项类型,并确保SelectedValue或SelectedItem确实是ReferenceEquals或Equals与ItemsSource中的一个项目。现在,我再次将这一点再次归结为对WPF中合理的绑定错误反馈的不良支持。

答案 2 :(得分:0)

我为此问题苦苦挣扎了大约一个星期,但仍然不知道是什么原因导致了组合框的这种奇怪行为。

在针对组合框的ItemsSource(@Jeronimo the Black情况)提出OnPropertyChanged之后,传统的组合框控件无法识别SelectedItem仍在基础集合中。然后,控件内部将SelectedItem = NULL设置为空,UI显示为空白。棘手的事情是,这种行为具有50%的可重现性,切换到另一个对象或模型后,ItemsSource和SelectedItem之间的互连可以自我恢复。

就我而言,即使是ItemsSource过滤也导致了这些错误。请注意,ParentRegionId属性具有Nullable类型。

例如1个无空格

    public IEnumerable CityDisplayList
    {
        get
        {
            if (_selectedCity != null && _selectedCity.ParentRegionId != null)
            {
                return ItemsSource.Where(x => x.ParentRegionId != null);
            }

            return Enumerable.Empty<TRegion>();
        }
    }

例如2个50%的空白(附加过滤)

    public IEnumerable CityDisplayList
    {
        get
        {
            if (_selectedCity != null && _selectedCity.ParentRegionId != null)
            {
                return ItemsSource.Where(x => x.ParentRegionId != null && x.ParentRegionId == _selectedCity.ParentRegionId);
            }

            return Enumerable.Empty<TRegion>();
        }
    }

例如3个50%的空格(在绑定语句中,IsAsync = True)

ItemsSource="{Binding CityDisplayList, Mode=OneWay, IsAsync=True}"

我支持@jpierson的想法,如果您的基础集合和SelectedItem是在不同的类实例中创建的或当它们具有不同的数据上下文源时,最好不要使用SelectedItem。例如,我使用依赖项属性将SelectedItem传递到UserControl。但是,ItemsSource是其他UC上下文的一部分。

解决此问题的最简单方法就是忘记SelectedItem属性:

<ComboBox x:Name="cbxCity" ItemsSource="{Binding CityDisplayList}" DisplayMemberPath="RegionName"
              SelectedItem="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ctrl:ControlRegionCombobox}}, Path=SelectedCity}" />

,并改为使用“ SelectedValue” +“ SelectedValuePath”:

<ComboBox x:Name="cbxCity" ItemsSource="{Binding CityDisplayList}" DisplayMemberPath="RegionName"
              SelectedValue="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ctrl:ControlRegionCombobox}}, Path=SelectedCity.Id}"
              SelectedValuePath="Id" />