WPF,MVVM从字典中填充级联组合框

Posted

技术标签:

【中文标题】WPF,MVVM从字典中填充级联组合框【英文标题】:WPF, MVVM Populating Cascading ComboBoxes from a dictionary 【发布时间】:2022-01-06 08:14:26 【问题描述】:

所以,我有一个包含 2 个组合框的 UserControl,我想从字典中填充它们。所以 ComboBoxA 被字典键填充,而 ComboBoxB 被字典[ComboBoxA selected item] 填充。如何使用 MVVM 实现这一目标? Category 基本上是 int,Parameter 是一个字符串。 到目前为止我的代码:模型

public class CategoryUserControlModel
    
        public Dictionary<Category, List<Parameter>> parametersOfCategories  get; set;
        public Category chosenCategory  get; set; 
        public Parameter chosenParameter  get; set; 
    

视图模型

public class CategoryUserControlViewModel
    

        public CategoryUserControlViewModel(CategoryUserControlModel controlModel)
        
            Model = controlModel;
        
        public CategoryUserControlModel Model  get; set; 

        public Category ChosenCategory
        
            get => Model.chosenCategory;
            set
            
                Model.chosenCategory = value;
            
        

        public Parameter ChosenParameter
        
            get => Model.chosenParameter;
            set => Model.chosenParameter = value;
        
    

XAML

  <Grid>
    <ComboBox x:Name="Categories" HorizontalAlignment="Left" Margin="0,14,0,0" VerticalAlignment="Top" Width="120" ItemsSource="Binding Model.parametersOfCategories.Keys"/>
    <TextBlock x:Name="Text" HorizontalAlignment="Left" Height="15" Margin="0,-2,0,0" TextWrapping="Wrap" Text="Категория" VerticalAlignment="Top" Width="60"/>
    <ComboBox x:Name="Parameter" HorizontalAlignment="Left" Margin="125,14,0,0" VerticalAlignment="Top" Width="120" ItemsSource="Binding Model.parametersOfCategories.Values/>
    <TextBlock x:Name="ParameterText" HorizontalAlignment="Left" Height="15" Margin="125,-2,0,0" TextWrapping="Wrap" Text="Параметр" VerticalAlignment="Top" Width="60"/>
  </Grid>
</UserControl>

【问题讨论】:

【参考方案1】:

您为模型和视图模型使用了不恰当的名称,它们不应该与视图相关联,并且您的模型不应该包含名称给人以模型需要用户交互的印象的成员。考虑一个类似于这个的改进版本:

public class CategoryWithParameterModel

    public Dictionary<Category, List<Parameter>> ParametersOfCategories  get; set;
    public Category Category  get; set; 
    public Parameter Parameter  get; set; 

您的 viewmodel 必须实现 INotifyPropertyChanged 接口,以便通知 UI 它需要刷新绑定,这对于模型来说不是必需的,因为您将它包装在 viewmodel 中。也就是说,您的视图模型定义将变为:

public class CategoryWithParameterViewModel : INotifyPropertyChanged
 ... 

接下来,既然你想绑定到字典中的一个列表,那么你的视图模型必须公开一个指向该列表的属性,我们称之为AvailableParameters,所以它应该这样定义:

public List<Parameter> AvailableParameters

    get
    
        if (Model.ParametersOfCategories.ContainsKey(ChosenCategory))
            return Model.ParametersOfCategories[ChosenCategory];
        else
            return null;
    

这是需要绑定到名为“参数”的第二个组合框的ItemsSource 的属性:)

但是,ChosenCategory 属性根本没有绑定,因此您需要将其绑定到第一个组合框的选定项,以便能够检测允许 viemodel 查找参数列表的用户选择,同样适用于 @ 987654328@,所以这里是更新的xaml代码:

<Grid>
  <ComboBox x:Name="Categories" HorizontalAlignment="Left" Margin="0,14,0,0" VerticalAlignment="Top" Width="120" ItemsSource="Binding Model.ParametersOfCategories.Keys" SelectedItem="Binding ChosenCategory"/>
  <TextBlock x:Name="Text" HorizontalAlignment="Left" Height="15" Margin="0,-2,0,0" TextWrapping="Wrap" Text="Категория" VerticalAlignment="Top" Width="60"/>
  <ComboBox x:Name="Parameter" HorizontalAlignment="Left" Margin="125,14,0,0" VerticalAlignment="Top" Width="120" ItemsSource="Binding AvailableParameters" SelectedItem="Binding ChosenParameter"/>
  <TextBlock x:Name="ParameterText" HorizontalAlignment="Left" Height="15" Margin="125,-2,0,0" TextWrapping="Wrap" Text="Параметр" VerticalAlignment="Top" Width="60"/>
</Grid>

最后,您必须在 ChosenCategory 发生更改时通知 UI,因此您需要为 AvailableParameters 引发 PropertyChanged 事件。实现它将使视图模型变成这样:

public class CategoryWithParameterViewModel : INotifyPropertyChanged

    public CategoryWithParameterViewModel(CategoryWithParameterModel model)
    
        Model = model;
    

    // This should be read-only
    public CategoryWithParameterModel Model  get; /*set;*/ 

    public Category ChosenCategory
    
        get => Model.Category;
        set
        
            Model.Category = value;
            OnPropertyChanged(nameof(AvailableParameters));
        
    

    public Parameter ChosenParameter
    
        get => Model.Parameter;
        set => Model.Parameter = value;
    

    public List<Parameter> AvailableParameters
    
        get
        
            if (Model.ParametersOfCategories.ContainsKey(ChosenCategory))
                return Model.ParametersOfCategories[ChosenCategory];
            else
                return null;
        
    

    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyName)
    
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    

【讨论】:

以上是关于WPF,MVVM从字典中填充级联组合框的主要内容,如果未能解决你的问题,请参考以下文章

WPF MVVM:组合框 SelectedValue 绑定

访问级联组合框自动填充当留下一个选项时

我如何在wpf mvvm中使用组合框

WPF 基于组合框选择使用 MVVM 改变窗口布局

在 MVVM 中的 Datagrid 中绑定 WPF 组合框不保存更改

组合框级联效应不适用于不同的行