使用 MVVM 时,绑定不适用于 ListBox

Posted

技术标签:

【中文标题】使用 MVVM 时,绑定不适用于 ListBox【英文标题】:Binding isn't working for ListBox while using MVVM 【发布时间】:2015-11-06 00:19:25 【问题描述】:

我有一个简单的 UserControl,带有一个显示 V14、V15 等版本的下拉菜单。

我有另一个 ListBox,它的 ItemSource 绑定到 ViewModel 中的一个属性,该属性取决于 Version DropDown 的 SelectedValue。

ViewModel 看起来像这样:

 class MultiSelectEnvironmentContextControlViewModel: ViewModelBase
    
        private string selectedVersion;
        private DomainFacade domainFacade;
        private ObservableCollection<string> environments= new ObservableCollection<string>(); 

        public MultiSelectEnvironmentContextControlViewModel()
        
            domainFacade = ((App) Application.Current).DomainFacade;

        
        public IEnumerable<string> EnvironmentVersions
        
            get
            
                return (domainFacade.GetEnvironmentVersions().Select(v => "Version " + v));
            
            

        public string SelectedVersion
        
            get  return selectedVersion; 
            set
            
                selectedVersion = value;
                RaisePropertyChanged("Environments");
            
        


                 public ObservableCollection<string> Environments
    
        get
        
            environments = (ObservableCollection<string>)(domainFacade.GetEnvironments(SelectedVersion));
            return environments;
        
    

    

我正在跟踪一个属性中的 SelectedVersion,该属性会在 Environments 上引发 PropertyChanged,以便每当 SeelectedVersion 发生变化时,Environments 都应该更新 UI。

我面临的问题是,我运行应用程序,我看到正在填充的版本,但 ListBox 中没有任何内容。

我在 UserControl 的构造函数中将 UserControl 的 DataContext 设置为 ViewModel。

这是我的 Control.cs 文件的样子:

 public partial class MultiSelectEnvironmentContextControl : UserControl
                
        private static MultiSelectEnvironmentContextControlViewModel dataContext = new MultiSelectEnvironmentContextControlViewModel();

        public MultiSelectEnvironmentContextControl()
        
            InitializeComponent();
            this.DataContext = dataContext;
           dataContext.SelectedVersion = (string)this.ComboBoxVersions.SelectedItem;

                      

        private void ComboBoxVersions_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
        
          dataContext.SelectedVersion = ((ComboBox) sender).SelectedValue.ToString();              
        

这是 XAML:

    <ComboBox Grid.Column="0" Grid.Row="0" x:Name="ComboBoxVersions" SelectedIndex="0" Margin="10" SelectionChanged="ComboBoxVersions_OnSelectionChanged" ItemsSource="Binding EnvironmentVersions">
        <ComboBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="Binding" />
            </DataTemplate>
        </ComboBox.ItemTemplate>
    </ComboBox>

    <StackPanel Orientation="Horizontal" Grid.Column="1" Grid.Row="0" Margin="10">
        <TextBlock VerticalAlignment="Center" Margin="0,0,10,0">Tests to be run for:</TextBlock>
        <ComboBox  Name="ComboBoxFileTypeSelector" ItemsSource="Binding AvailableValidationTypes" DisplayMemberPath="Key" SelectedValuePath="Value" SelectedIndex="0">
        </ComboBox>
    </StackPanel>

    <ListBox x:Name="ListBoxEnvironments" Grid.Column="0" Grid.Row="1" Height="300" Grid.ColumnSpan="2" HorizontalAlignment="Stretch" Margin="10" SelectionMode="Multiple" ItemsSource="Binding Environments">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel Orientation="Horizontal" HorizontalAlignment="Left" Width="800" >
                </WrapPanel>
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
        <ListBox.ItemTemplate>
            <DataTemplate>
                <CheckBox x:Name="CheckBoxEnvironment" Content="Binding" IsChecked="Binding RelativeSource=RelativeSource AncestorType=x:Type ListBoxItem, Path=IsSelected" Margin="5">
                </CheckBox>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>

【问题讨论】:

您能否将您的 XAML 发布为列表框,以便我们查看您如何绑定前端 问题可能在于您如何声明数据上下文代码隐藏。使用 MVVM 的目的是不要在 UI 元素 .cs 文件中编写代码。您应该改为在 XAML 中声明数据上下文和绑定。 Environments 属性获取器返回一个新的ObservableCollection&lt;string&gt; 是一个非常糟糕的主意。如果多次调用该属性,您将处理该集合的多个不同实例。 什么?这仍然会在每次调用时创建一个新实例。 您是否尝试过在 Environments 属性 getter 中添加断点,调试它并查看它是否在应该填充列表框时被命中?调试应用程序时在 VS 的输出窗口中写入了什么(菜单->调试->Windows->输出)? 【参考方案1】:

我认为这是因为 SelectedVersion 具有“版本 1”、“版本 2”等值,但您的方法 DomainFacade.GetEnvironments(string version) 需要“1”、“2”等值。

我会这样写你的视图模型:

public class MultiSelectEnvironmentContextControlViewModel : ViewModelBase

    private string selectedVersion;
    private DomainFacade domainFacade;
    private IEnumerable<string> environments;

    public MultiSelectEnvironmentContextControlViewModel()
    
        domainFacade = ((App)Application.Current).DomainFacade;
        EnvironmentVersions = domainFacade.GetEnvironmentVersions();
    

    public IEnumerable<string> EnvironmentVersions  get; private set; 

    public string SelectedVersion
    
        get  return selectedVersion; 
        set
        
            selectedVersion = value;
            RaisePropertyChanged("SelectedVersion");
            Environments = domainFacade.GetEnvironments(SelectedVersion);
        
    

    public IEnumerable<string> Environments
    
        get  return environments; 
        set
        
            environments = value;
            RaisePropertyChanged("Environments");
        
    

并应用于视图中环境版本的格式化:

<ComboBox SelectedItem="Binding SelectedVersion"
          ItemsSource="Binding EnvironmentVersions"
          ItemStringFormat="Version: 0" />

【讨论】:

以上是关于使用 MVVM 时,绑定不适用于 ListBox的主要内容,如果未能解决你的问题,请参考以下文章

XAML 绑定不适用于依赖属性?

雄辩的 whereRaw 不适用于绑定

ASP.NET Web API - 模型绑定不适用于 POST 上的 XML 数据

两种方式的数据绑定不适用于淘汰 Observable Arrays

Bootstrap 多选不适用于剔除绑定

PDO 案例存在不适用于绑定参数