从 ViewModel WPF 更新 XAML 中的 ComboBox ObservableCollection 绑定

Updating ComboBox ObservableCollection Binding in XAML from ViewModel WPF

我在 WPF 中工作,并且有一个视图模型 ModifiedReasonViewModel,这是我的 DataContext 的 XAML 视图。 ComboBox 不显示我在调试时可以在数据上下文中看到的 4 个项目中的任何一个。我认为这肯定与我异步拉取原因标签这一事实有关。关于如何解决此问题的任何想法?

当我仅使用在构造函数中初始化的测试字符串列表测试此代码时,它按预期工作。

这是我目前在 XAML 中使用的 RadComboBox

d:DataContext="{d:DesignInstance Type=vm:ATMModifiedReasonViewModel, IsDesignTimeCreatable=True}">
<telerik:RadComboBox Name="ReasonCmbo"
                     ItemsSource="{Binding ReasonLabels}" 
                     DisplayMemberPath="Name"
                     IsEditable="False"
                     Margin="2" 
                     Grid.Column="1"
                     Grid.Row="1"
                     Grid.ColumnSpan="2">            
</telerik:RadComboBox>

这是我正在使用的 ViewModel 代码:

public class ATMModifiedReasonViewModel : INotifyPropertyChanged
{
   private List<LabelFileModel> _reasonLabels;

   public List<LabelFileModel> ReasonLabels { get { return _reasonLabels; } set { _reasonLabels = value; } }

   public ATMModifiedReasonViewModel(){
      GetReasonLabels();
   }

   public void GetReasonLabels()
   {
      LabelFileProvider lfProvider = new LabelFileProvider();
      LabelFileModelFilter filter = new LabelFileModelFilter() {LabelDefinition = "ModifiedReason"};
      lfProvider.GetFiltered(filter,10, getResult => GetReasonLabelsCallback(getResult));
   }

   private void GetReasonLabelsCallback(Func<IEnumerable<LabelFileModel>> getResult)
   {
       try
       {
            _reasonLabels = (List<LabelFileModel>) getResult();                
       }   
       catch (Exception ex)
       {
            Messenger.Default.Send(new UnhandledExceptionMessage(this, ex));
       }
   }
}

非常感谢您的帮助!

如果您在运行时重新分配 ReasonLabels 集合,则必须实现 INotifyPropertyChanged and raise the PropertyChanged 事件,否则绑定将不会注意到更改。

同样,如果您修改集合本身,例如添加或删除项目,集合需要实现 INotifyCollectionChanged, which provides events to trigger an update in the user interface. The List<T> type does not implement this interface, use ObservableCollection<T> instead. It automatically raises the CollectionChanged 事件,如果集合被修改并因此触发绑定更新。

public class ATMModifiedReasonViewModel : INotifyPropertyChanged
{
   private ObservableCollection<LabelFileModel> _reasonLabels;

   public ObservableCollection<LabelFileModel> ReasonLabels
   {
      get => _reasonLabels;
      set
      {
         if (_reasonLabels = value)
            return;

         _reasonLabels = value;
         OnPropertyChanged();
      } 
   }

   // ...your code here.

   public event PropertyChangedEventHandler PropertyChanged;

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

您还必须分配 ReasonLabels 属性 而不是支持字段 _reasonLabels,否则 属性 setter 会触发 PropertyChanged 事件不会被执行。

private void GetReasonLabelsCallback(Func<IEnumerable<LabelFileModel>> getResult)
{
   try
   {
      ReasonLabels = (List<LabelFileModel>) getResult();                
   }   
   catch (Exception ex)
   {
      Messenger.Default.Send(new UnhandledExceptionMessage(this, ex));
   }
}

在回调中设置 属性 并从它的 setter 引发 PropertyChanged 事件,或者在 PropertyChanged 设置支持字段后回调中的事件:

private void GetReasonLabelsCallback(Func<IEnumerable<LabelFileModel>> getResult)
{
    try
    {
        _reasonLabels = (List<LabelFileModel>)getResult();
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ReasonLabels )));
    }
    catch (Exception ex)
    {
        Messenger.Default.Send(new UnhandledExceptionMessage(this, ex));
    }
}

框架需要引发事件才能知道何时刷新 UI。