【问题标题】:Combo-box loses selection after collection changes集合更改后组合框丢失选择
【发布时间】:2012-03-22 01:58:48
【问题描述】:

我有一个绑定到可观察集合 (OC) 的 WPF 组合框:

    <ComboBox Name="cbCombination" ItemsSource="{Binding Combinations}" 
              SelectedIndex="0" />

在其他地方,在作为数据上下文的对象集中:

    public ObservableCollection<Combination> Combinations { get; set; }

Combination 覆盖了它的 ToString 并且一切都很好:组合框的下拉列表显示了 Combinations OC 中的所有组合项。组合框的选择框显示第一个组合的值。

现在,数据上下文对象必须更改其组合 OC 中的值:

    var combinationsList = CombinationsManager.CombinationsFor(someParam);
    this.Combinations.Clear();
    foreach (var combination in combinationsList)
        this.Combinations.Add(combination);
    NotifyPropertyChanged(@"Combinations");

这会导致组合框的选择框显示一个空字符串。 (下拉列表已关闭。但是,当我将其下拉时,它确实显示了正确的新组合,因此它绑定到更新的集合。

我试图捕获 SourceUpdated 和(令我失望的)TargetUpdated 事件(想在那里设置 SelectedIndex),但我的事件处理程序没有被调用!

所以我的问题是:当 WPF ComboBox 绑定到的可观察集合发生变化时,如何让 WPF ComboBox 刷新其选择框的值?

更新

我完全忘了提及,我不知道它是否重要,但组合框位于 UserControl 中。 UserControl 的 XAML 如下所示:

<UserControl x:Class="...CombinationsToolBar"
         .... mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
<ToolBarTray Name="toolBarTray1" >
    <ToolBar Name="toolBar1">
        <ComboBox Name="cbCombination" 
         ItemsSource="{Binding Path=Combinations, NotifyOnSourceUpdated=True, 
                                                                     IsAsync=True}"
            SelectedIndex="0" IsEditable="False"  
            SelectionChanged="CbCombinationSelectionChanged"
            SourceUpdated="CbCombinationSourceUpdated"
            TargetUpdated="CbCombinationTargetUpdated"></ComboBox>
    </ToolBar>
</ToolBarTray>

在 UserControl 的代码中我在 CbCombinationSelectionChanged、CbCombinationSourceUpdated 和 CbCombinationTargetUpdated 上有断点。

CbCombinationSelectionChanged 在首次加载包含用户控件的表单时触发一次。正如@asktomsk 所说,在清除组合集合时确实会第二次调用它。

不触发更新的源和更新的目标 - 不调用 CbCombinationSourceUpdated 和 CbCombinationTargetUpdated。

由于组合框在用户控件内,而 Combinations 集合在视图模型内,并且视图模型无权访问组合框,我没有机会设置选定的索引组合,除非事件触发

:(

【问题讨论】:

    标签: wpf combobox observablecollection


    【解决方案1】:

    问题出在你的this.Combinations.Clear();
    当你这样做时,它会设置SelectedItem = nullSelectedIndex = -1

    所以你应该再次设置选择。如果您有权访问您的 ComboBox,则只需在填写组合列表后写此 cbCombination.SelectedIndex = 0;
    当然,您也可以将 SelectedItem/SelectedIndex 绑定到代码中的某些属性。

    顺便说一句
    此外,在填充集合后不需要调用NotifyPropertyChanged(@"Combinations");,因为Combinations 已经实现了INotifyPropertyChanged

    更新

    要检测您的 ObservableCollection 已更改,请在后面的 UserControl 代码中订阅 CollectionChanged 事件。请确保您集合更改之前订阅了!

    Combinations.CollectionChanged += (s, e) =>
    {
        if (cbCombination.Items.Count > 0)
            cbCombination.SelectedIndex = 0;
    };
    

    另一个建议

    当您不需要更智能的逻辑而不只是在组合框中选择零索引时,上述方法适用。 但通常您需要更复杂的逻辑来选择某些项目。在这种情况下,您可以向模型添加新属性:

    public Combination SelectedCombination
    {
        get{ return _selectedCombination; }
        set
        {
            _selectedCombination = value;
            NotifyPropertyChanged("SelectedCombination");
        }
    }
    

    并将此属性绑定到您的组合框:

    <ComboBox Name="cbCombination" ItemsSource="{Binding Combinations}" 
              SelectedIndex="0" SelectedItem={Bindings SelectedCombination} />
    

    在这种情况下,您可以在填充 Combinations 集合时选择任何项目,它将在组合框中自动选择:

    var combinationsList = CombinationsManager.CombinationsFor(someParam);
    this.Combinations.Clear();
    foreach (var combination in combinationsList)
        this.Combinations.Add(combination);
    
    if (Combinations.Count > 0)
        SelectedCombination = Combinations[0];
    

    【讨论】:

    • 谢谢,但是:我正在尝试再次设置选择,但是如何?什么应该唤醒我将修改 SelectedItem 和/或 SelectedIndex 的代码?我的整个问题是组合框的 SourceUpdated 事件没有触发!
    • 它可能会触发,但您在组合的设置器中放置了一个断点,并且如果集合发生更改,它将不会触发,只有当您为其分配另一个集合时。在代码中使用 selectedindex、selectedvalue 或 selecteditem。
    • 我已经更新了答案。如果仍然不足以解决问题,请告诉我。
    • 在这种情况下,您可以使用 ObservableCollection 类的 CollectionChanged 事件。看看更新的答案。
    猜你喜欢
    • 1970-01-01
    • 2014-01-07
    • 1970-01-01
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    • 2012-01-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多