【问题标题】:How do you bind a collection of items to a list box of checkboxes?如何将项目集合绑定到复选框列表框?
【发布时间】:2011-03-23 10:09:25
【问题描述】:

抱歉描述的模糊,我想不出更好的表达方式。

假设我的 ViewModel 有如下属性:

public List<MyClass> SubSystems { get; set; }

和 SubSystems 类:

public class SubSystem
{
    public string Name { get; set; }

    public bool IsSelected { get; set; }
}

在视图中,我想将SubSystems 属性绑定到一个复选框列表,其中 CheckBox 的 IsChecked 和 Name 属性绑定到它们各自的属性 IsChecked 为 IsSelected和名称的内容。

我知道我可以在 XAML 中创建一个 ListBox,但我不确定我将如何使用绑定和集合来执行此操作..

感谢您的帮助!

编辑 -

这是 XAML:

<GroupBox Header="Sub-Systems" Grid.Column="0" Grid.Row="0" Margin="5">
    <Grid>
        <Grid.Resources>
            <DataTemplate x:Key="checkBox">
                <StackPanel Orientation="Horizontal">
                    <CheckBox IsChecked="{Binding IsSelected}" />
                    <TextBlock Text="{Binding Name}" />
                </StackPanel>
            </DataTemplate>
        </Grid.Resources>
        <ListBox ItemTemplate="{StaticResource checkBox}" ItemsSource="{Binding SubSystems}" />
    </Grid>
</GroupBox>

编辑 #2 -

澄清一下,所有示例都填充了该框,但没有一个示例在设置器中的断点处中断。

【问题讨论】:

  • 您还需要 NotifyPropertyChanged 以防您的 SubSystem 对象在其他地方发生更改,它应该通知 CheckBox 它已更改,因此 CheckBox 可以自行更新。

标签: c# wpf visual-studio-2008 .net-3.5


【解决方案1】:

我认为您可能需要ItemsControl 而不是ListBox。 ListBoxes 假设您想选择SubSystem 之一,但实际上,您只想使用数据模板排列项目:

<ItemsControl ItemsSource="{Binding SubSystems}">
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <Checkbox IsChecked="{Binding IsSelected, Mode=TwoWay}" Content="{Binding Name}" />
    </DataTemplate>
  <ItemsControl.ItemTemplate>
</ItemsControl>

【讨论】:

    【解决方案2】:

    这个怎么样:

    <DataTemplate>
        <StackPanel Orientation="Horizontal">
            <CheckBox IsChecked={Binding IsSelected, Mode=TwoWay} /><TextBlock Text={Binding Name} />
        </StackPanel>
    </DataTemplate>
    

    【讨论】:

    • 由于某种未知原因,在我的 ViewModel 中,当我使用它时,setter 永远不会被调用。我将 x:Key="checkBox" 添加到 并将 ItemTemplate="{StaticResource checkBox}" 添加到 ListBox。它似乎可以正确呈现,只是没有绑定。
    • 啊,是的,已修复。 Mode=TwoWay 是您所缺少的
    • @Ian P:我认为您缺少的是绑定中的 ElementName 属性,DataTemplate 不知道 SubSystems 属性的来源,您需要这个:ItemsSource="{Binding ElementName=window1, Path=SubSystems}”,看我的答案底部
    【解决方案3】:

    你的意思是这样的吗?

    子系统类

    public class SubSystem : INotifyPropertyChanged
    {
        private string mName;
        private Boolean mIsSelected = false;
    
        public SubSystem()
        {
        }
    
        public SubSystem(string name, Boolean isSelected)
        {
            this.Name = name;
            this.IsSelected = isSelected;
        }
    
        public string Name
        {
            get { return mName; }
            set
            {
                if (mName != value)
                {
                    mName = value;
                    if (PropertyChanged != null)
                        PropertyChanged(this, new PropertyChangedEventArgs("Name"));
                }
            }
        }
    
        public Boolean IsSelected
        {
            get { return mIsSelected; }
            set
            {
                if (mIsSelected != value)
                {
                    mIsSelected = value;
                    if (PropertyChanged != null)
                        PropertyChanged(this, new PropertyChangedEventArgs("IsSelected"));
                }
            }
        }
    
        #region INotifyPropertyChanged Members
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        #endregion
    }
    

    视图模型

    ObservableCollection<SubSystem> mSubSystems = new ObservableCollection<SubSystem>();
    public ObservableCollection<SubSystem> SubSystems
    {
        get { return mSubSystems; }
        set { mSubSystems = value; }
    }
    

    查看

    <ListBox x:Name="lstSubsystems" ItemsSource="{Binding SubSystems}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <CheckBox IsChecked="{Binding IsSelected}">
                    <ContentPresenter Content="{Binding Name}"  />
                </CheckBox>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
    

    希望对您有所帮助, 重量

    【讨论】:

    • @Ian P:记得在 CheckBox 上设置 Focusable="False",这样您的用户就无法使用 tab 键进入它,否则它看起来和感觉真的很奇怪。
    【解决方案4】:

    修改 ListBox.ItemTemplate 以使用复选框,并将 CheckBox.IsChecked 绑定到 SubSystem.IsSelected 并将 CheckBox.Content 绑定到 SubSystem.Name:

    XAML:

    <ListBox ItemsSource="{Binding}">
      <ListBox.ItemTemplate>
       <DataTemplate>
        <CheckBox IsChecked="{Binding IsSelected}" Content="{Binding Name}" Margin="5" Focusable="False" />
       </DataTemplate>
      </ListBox.ItemTemplate>
     </ListBox>
    

    C#:

    private void window1_Loaded(object sender, RoutedEventArgs e)
    {
     this.SubSystems = new List<SubSystem>();
    
     this.SubSystems.Add(new SubSystem() { Name = "SubSystem 1", IsSelected = false });
     this.SubSystems.Add(new SubSystem() { Name = "SubSystem 2", IsSelected = false });
     this.SubSystems.Add(new SubSystem() { Name = "SubSystem 3", IsSelected = true });
     this.SubSystems.Add(new SubSystem() { Name = "SubSystem 4", IsSelected = false });
     this.SubSystems.Add(new SubSystem() { Name = "SubSystem 5", IsSelected = true });
    
     this.DataContext = this.SubSystems;
    }
    

    并确保将 Focusable="False" 设置为 CheckBoxes,否则您的用户将能够使用 Tab 进入它们。

    编辑:

    此外,根据您添加的内容,您可能缺少 ElementName 属性(如果 SubSystems 不是窗口的 DataContext,则需要使用 ElementName 绑定属性指定 SubSystems 属性的来源):

     <ListBox ItemTemplate="{StaticResource checkBox}" ItemsSource="{Binding ElementName=window1, Path=SubSystems}" />
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-04
      • 2011-12-23
      相关资源
      最近更新 更多