【问题标题】:WPF combo box does not update currently selected itemWPF 组合框不更新当前选定的项目
【发布时间】:2017-08-31 23:42:54
【问题描述】:

我的组合框有问题。不知何故,它可能会与自身不同步。例如,在我更改了我的 BlockSequenceFields 后,只有下拉文本被更改。下面,字段 1 已更新,但您可以看到它没有反映在当前选定的项目中。

我的 IsSynchronizedWithCurrentItem=true 应该使当前选定的项目按预期运行,但它似乎不起作用。我已经阅读了许多当前项目不匹配的 stackoverflow 帖子,但他们只是将 IsSynchronizedWithCurrentItem 设置为 true 并解决了他们的问题。

谁能解释为什么这对我不起作用?

    <ComboBox x:Name="SequenceFieldComboBox" 
              SelectedItem="{Binding BlockSequenceFieldIndex, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
              ItemsSource="{Binding BlockSequenceFields, UpdateSourceTrigger=PropertyChanged}"   
              IsSynchronizedWithCurrentItem="True">

        <ComboBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <CheckBox
                        IsChecked="{Binding IsCalibrated, Mode=OneWay}"
                        IsEnabled="False">
                    </CheckBox>
                    <TextBlock 
                        Text="{Binding}">
                    </TextBlock>
                </StackPanel>
            </DataTemplate>
        </ComboBox.ItemTemplate>
    </ComboBox>

编辑:张伯伦先生的更多细节

// ViewModelBase implements INotifyPropertyChanged
public class BlockFieldViewModel : ViewModelBase
{
    public BlockSequenceField SequenceField { get; set; }

    public List<BlockSequenceCalibrationItemViewModel> Calibrations => this.SequenceField?.CalibrationList;

    public bool IsCalibrated => this.Calibrations.TrueForAll(x => x.IsCalibrated == null || x.IsCalibrated == true);

    public double AmplitudeThreshold => this.Calibrations.Max(x => x.Amplitude);

    public int FieldNumber { get; set; }

    public override string ToString()
    {
        string ret = string.Format(CultureInfo.CurrentCulture, "Field {0} ", this.FieldNumber);

        if (Math.Abs(this.AmplitudeThreshold) > .00001)
        {
            ret = string.Concat(ret, string.Format(CultureInfo.CurrentCulture, "({0} mA)", this.AmplitudeThreshold));
        }

        return ret;
    }
}

这是更大的视图模型,称为 MainViewModel.cs。以下是类中的相关字段

    private ObservableCollection<BlockFieldViewModel> blockSequenceFields;

    public ObservableCollection<BlockFieldViewModel> BlockSequenceFields
    {
        get => this.blockSequenceFields;
        set
        {
            this.blockSequenceFields = value;
            this.OnPropertyChanged("BlockSequenceFields");
        }
    }

    private void RefreshFieldList()
    {
        // In order for the combo box text to update, we need to reload the items
        var savedIndex = this.BlockSequenceFieldIndex;  // to restore to current field.
        var fieldList = this.CalibrationViewModel.FieldViewModels;
        this.BlockSequenceFields = new ObservableCollection<BlockFieldViewModel>(fieldList); 
        this.BlockSequenceFieldIndex = savedIndex;
    }

【问题讨论】:

  • 请向我们展示您的 DataContext 为组合框设置的视图模型。我在你的public ObserveableCollection&lt;T&gt; BlockSequenceFields { get; }中寻找T类的代码
  • 也许你忘了给你的 viewModel 添加 INotifyPropertyChanged 接口?
  • @ScottChamberlain 我相当确定作为组合框更新的一部分,datacontext 设置正确。但是,我将明确设置数据上下文并查看它是否有效。我没有代码隐藏文件来设置数据上下文,所以我将在 xaml 中进行。
  • @Demon,是的,我的虚拟机实现了 INotifyPropertyChanged。
  • @user2619824 我和 Daemon 有同样的顾虑,你的虚拟机可能会实现 INotifyPropertyChanged,但是 BlockSequenceFields 集合中的行项目是否也实现了 INotifyPropertyChanged?你能展示你的虚拟机,以及集合中任何项目的类吗?我并不关心数据上下文本身,我更关心视图模型中的数据类型。更具体地说,我想查看包含 IsCalibrated 属性的类的代码。

标签: c# wpf combobox


【解决方案1】:

您的问题是因为 BlockFieldViewModel 在 FieldNumber 更新时没有引发 INPC。您至少需要为该属性提高它。

//Assuming the base class looks like
public class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

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


public class BlockFieldViewModel : ViewModelBase
{
   //...

    public int FieldNumber 
    { 
        get
        {
            return _fieldNumber;
        }
        set
        {
            if(_fieldNumber.Equals(value))
                return;

            OnPropertyChanged();
        }
    }
    //...
}

我不确定这是否会解决您的问题,因为您使用 .ToString() 来显示名称。如果您发现上述方法无法修复,则通过将空字符串传递给您的 OnPropertyChanged 方法来触发整个对象的属性更改

public int FieldNumber 
{ 
    get
    {
        return _fieldNumber;
    }
    set
    {
        if(_fieldNumber.Equals(value))
            return;

        //Refresh all properties due to the .ToString() not updating.
        OnPropertyChanged("");
    }
}

另外,如果List&lt;BlockSequenceCalibrationItemViewModel&gt; Calibrations 可以添加或删除,或者.Amplitude 可以更改,您也需要触发刷新名称。

【讨论】:

  • @user2619824 你能添加BlockSequenceCalibrationItemViewModelBlockSequenceField的代码吗,我可以做一个完整的例子来解决所有问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-01-14
  • 2011-12-21
  • 1970-01-01
  • 2016-04-18
  • 1970-01-01
  • 1970-01-01
  • 2010-11-13
相关资源
最近更新 更多