【问题标题】:Property binding not working in ListBox WPF属性绑定在 ListBox WPF 中不起作用
【发布时间】:2016-08-20 12:18:17
【问题描述】:

我正在尝试用由包含复选框和文本块的网格组成的项目填充 ListBox。我最初只有一个复选框,但我需要将文本换行,因此我将其更改为带有复选框和文本块的网格,文本块进行文本换行。

当它只是复选框时,绑定有效,但现在不行。现在列表框中显示了正确数量的项目,但它只是一个未选中的复选框(即使我在后面的代码中将其设置为选中,见下文)和一个空白文本块。

XAML:

<ListBox 
    x:Name="lstCalibration" 
    Margin="304,95,78,24" 
    Background="#7FFFFFFF" 
    Width="211" 
    HorizontalAlignment="Center" 
    VerticalContentAlignment="Stretch" 
    ScrollViewer.HorizontalScrollBarVisibility="Disabled" 
    HorizontalContentAlignment="Stretch">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Grid Width="auto">
                <Grid.RowDefinitions>
                    <RowDefinition Height="auto"/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="auto"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <CheckBox 
                    Content="" 
                    Tag="{Binding Tag}" 
                    IsChecked="{Binding IsChecked}" 
                    Checked="CheckBoxCal_Checked" 
                    Unchecked="CheckBoxCal_Unchecked"
                    Grid.Row="0" Grid.Column="0"
                    />
                <TextBlock 
                    Tag="{Binding Tag}" 
                    Text="{Binding Text}" 
                    TextWrapping="Wrap"
                    Grid.Row="0" 
                    Grid.Column="1"
                    />
            </Grid>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

背后的代码:

foreach (Controller item in calList)
{
    //fill listbox with cals and correct checked states
    Grid grid = new Grid();
    CheckBox cb = new CheckBox();
    TextBlock tb = new TextBlock();
    tb.Text = item.Description;
    cb.Tag = tb.Tag = i;
    cb.IsChecked = calChecked[i];
    if (cb.IsChecked == true)
        noneChecked = false;
    i++;

    Grid.SetRow(cb, 0);
    Grid.SetColumn(cb, 0);
    grid.Children.Add(cb);
    Grid.SetRow(tb, 0);
    Grid.SetColumn(tb, 1);
    grid.Children.Add(tb);
    lstCalibration.Items.Add(grid);
}

【问题讨论】:

    标签: c# wpf xaml data-binding listbox


    【解决方案1】:

    添加这个,并删除你以编程方式创建你在DataTemplate 中设置的所有内容的 foreach 循环。这是一个非常好的DataTemplate,但是您的代码没有正确使用它。 摆脱calChecked; _items[n].IsChecked 现在将完成这项工作。

    您可以随时向_items 添加一个新的ListItem,它会出现在列表中,或者删除一个现有的,它将从列表中消失。那是“可观察”的部分。感谢PropertyChanged 事件引发,如果您在后面的代码中设置IsChecked,UI 中的相应复选框将自动更新。

    public class ListItem : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    
        public String Text { get; set; }
    
        private bool _isChecked = false;
        public bool IsChecked {
            get { return _isChecked; }
            set {
                _isChecked = value;
                PropertyChanged?.Invoke(this, 
                    new PropertyChangedEventArgs(nameof(IsChecked));
            }
        }
    }
    

    在后面代码中的构造函数中:

    private ObservableCollection<ListItem> _items;
    public MyWindow()
    {
        InitializeComponent()
    
        _items = new ObservableCollection<ListItem>(
            calList.Select(
                cal => new ListItem {
                           Text = cal.Description,
                           IsChecked = cal.WhateverElse
                       }
            ));
    
        lstCalibration.Items = _items;
    }
    

    在两个地方对DataTemplate 的一个小改动:不要浪费时间绑定Tag。在事件处理程序(您可能甚至不需要)中,只需像这样进行转换:

    public void CheckBoxCal_Checked(object sender, EventArgs args)
    {
        var listItem = ((FrameworkElement)sender).DataContext as ListItem;
    
        //  Do whatever. listItem.IsChecked will be up to date thanks 
        //  to the binding.
    }
    

    XAML:

                <CheckBox 
                    Content="" 
                    IsChecked="{Binding IsChecked}" 
                    Checked="CheckBoxCal_Checked" 
                    Unchecked="CheckBoxCal_Unchecked"
                    Grid.Row="0" Grid.Column="0"
                    />
                <TextBlock 
                    Text="{Binding Text}" 
                    TextWrapping="Wrap"
                    Grid.Row="0" 
                    Grid.Column="1"
                    />
    

    【讨论】:

    • foreach 循环实际上是必要的,因为(我应该在我的问题中指出这一点)变量 calList 不是指 ListBox 控制器,它是一个单独的 List 变量,我用来填充列表框。此外, calCheked 也是必要的,因为即使在 UI 更改后,它也会记住所有项目的检查状态。我仍然会尝试应用您的答案,如果有效,我会回复您。
    • @MikkelBang 我不知道什么是“列表框控制器”。我可以看到您正在使用 calList 来填充列表框;我正在向您展示一种更好的方法来做同样的事情。我明白你对calChecked 的意思。
    • 啊,现在我知道您在填充列表以及为什么我不需要 foreach 循环了,我的错,应该在回复之前再研究一下您的代码。 ListBox 控制器是 UI 元素 ListBox。
    • 绑定工作,感谢您的回答和快速回复。我必须用它来做一些我想要它做的事情,但你回答了我的问题。
    • @MikkelBang 你还需要它做什么?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-04-28
    • 1970-01-01
    • 2011-01-18
    • 2017-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多