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

Posted

技术标签:

【中文标题】从 ViewModel WPF 更新 XAML 中的 ComboBox ObservableCollection 绑定【英文标题】:Updating ComboBox ObservableCollection Binding in XAML from ViewModel WPF 【发布时间】:2021-01-24 01:51:17 【问题描述】:

我在 WPF 中工作,并且有一个视图模型 ModifiedReasonViewModel,它是我用于 XAML 视图的 DataContextComboBox 不显示我在调试时可以在数据上下文中看到的 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));
       
   

非常感谢您的帮助!

【问题讨论】:

将属性绑定到View的控件时,ViewModel需要实现INotifyPropertyChanged,以便通知View任何属性值的变化 我之前实现过。我已将其重新添加,但运气不佳。 经过一些测试,似乎实例化列表然后向其中添加项目允许视图解释更改并显示新项目?这看起来有可能吗? 【参考方案1】:

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

同样,如果您修改集合本身,例如添加或删除项目,集合需要实现INotifyCollectionChanged,它提供事件来触发用户界面中的更新。 List&lt;T&gt; 类型确实实现此接口,请改用 ObservableCollection&lt;T&gt;。如果集合被修改并因此触发绑定更新,它会自动引发 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,否则触发PropertyChanged 事件的属性设置器将不会被执行。

private void GetReasonLabelsCallback(Func<IEnumerable<LabelFileModel>> getResult)

   try
   
      ReasonLabels = (List<LabelFileModel>) getResult();                
      
   catch (Exception ex)
   
      Messenger.Default.Send(new UnhandledExceptionMessage(this, ex));
   

【讨论】:

【参考方案2】:

在您的回调中设置 属性 并从它的 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。

【讨论】:

以上是关于从 ViewModel WPF 更新 XAML 中的 ComboBox ObservableCollection 绑定的主要内容,如果未能解决你的问题,请参考以下文章

将 WPF xaml 绑定到 ViewModel 而不构造它

WPF TwoWay绑定在多个UserControl中

WPF 自定义一个控件,当点击按钮是触发到ViewModel(业务逻辑部分)和Xaml路由事件(页面逻辑部分)

如何从 ViewModel 更改样式属性?

WPF C# Ninject 与 mainViewModel 和多个 viewmodel 问题

WPF: WpfWindowToolkit 一个窗口操作库的介绍