集合更改后组合框丢失选择 [英] Combo-box loses selection after collection changes

查看:14
本文介绍了集合更改后组合框丢失选择的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a WPF combo box bound to an obvserable collection (OC):

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

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

Elsewhere, in the object set as data context:

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

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

Combination overrides its ToString and everything is peachy: The combo-box's drop-down displays all Combination items in the Combinations OC. The combo-box's selection box displays the value of the first Combination.

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

Now, the data-context object has to change the values in its Combinations OC:

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

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

This causes the combo-box's selection box shows an empty string. (The drop-down is closed. However, when I make it drop down, it does show the correct new Combinations, so it is bound to the updated collection).

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

I tried to capture both SourceUpdated and (in my dispair) TargetUpdated events (thining of setting the SelectedIndex there), but my event handlers didn't get called!

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

更新:

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

I've totally forgotten to mention, and I don't know whether it's important, but the combo-box is within a UserControl. The UserControl's XAML looks like this:

<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 上有断点.

In the UserControl's code I have breakpoints on CbCombinationSelectionChanged, CbCombinationSourceUpdated and CbCombinationTargetUpdated.

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

The CbCombinationSelectionChanged fires once when the form containing the user control is first loaded. It is indeed called a second time when the Combinations collection is cleared, as @asktomsk said.

不会触发源更新和目标更新 - 不会调用 CbCombinationSourceUpdated 和 CbCombinationTargetUpdated.

The source updated and target updated are not triggered - CbCombinationSourceUpdated and CbCombinationTargetUpdated are not called.

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

As the combo box is inside a usercontrol and the Combinations collection is within the view model, and as the view model doesn't have access to the combo box, I have no opportunity to set the selected index of the combo unless the events fire.

:(

推荐答案

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

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

So you should set selection again. If you have an access to your ComboBox then just write this cbCombination.SelectedIndex = 0; after filling Combinations list.
Of course you can bind SelectedItem/SelectedIndex to some property in code behind too.

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

BTW
Also it is not required to call NotifyPropertyChanged(@"Combinations"); after filling the collection because Combinations already implements INotifyPropertyChanged.

更新

要检测您的 ObservableCollection 是否已更改,请在您的 UserControl 代码后面订阅 CollectionChanged 事件.确保您在之前收藏更改订阅!

To detect that your ObservableCollection was changed, subscribe to CollectionChanged event in your UserControl code behind. Make sure that you subscribed before collection changed!

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

另一个建议

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

Approach above is works when you do not need a smarter logic than just select zero index in combobox. But often you will need a more complex logic to select some item. In this case you may add new property to your model:

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

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

and bind this property to your combobox:

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

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

In this case you can select any item when filling the Combinations collection and it will be automatically selected in combobox:

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

if (Combinations.Count > 0)
    SelectedCombination = Combinations[0];

这篇关于集合更改后组合框丢失选择的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆