【问题标题】:WPF ListBox not updating value of bound items when the items changeWPF ListBox在项目更改时不更新绑定项目的值
【发布时间】:2018-12-17 12:52:25
【问题描述】:

在应用程序中有一个绑定到 ObservableCollection 的 Listbox,然后将所选项目自身绑定到一些标签:当项目的属性在标签中更改时,实际对象(在本例中为 Multimedia)被更新(如我调试过)但是列表框没有更新显示的值。

Multimedia 类实现了 INotifyPropertyChanged,但我不确定我是否正确使用它。

其他一切都正常工作(添加按钮将一个新元素添加到列表中,并按应有的方式显示)。

我在不同的论坛和 stackoverflow 上环顾四周,并尝试了不同的变体,但仍然是属性,更新时,它不会在 ListBox 中更新。

这是 XMAL:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="135" />
        <RowDefinition Height="*" />
        <RowDefinition Height="45" />
    </Grid.RowDefinitions>
    <ListBox Name="mediaListBox"  ItemsSource="{Binding Path=MyData}" Grid.Row="0"/>
    <Grid Grid.Row="1"  DataContext="{Binding ElementName=mediaListBox, Path=SelectedItem}">

        ...

        <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Path=Title}" />
        <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Path=Artist}" />
        <TextBox Grid.Row="2" Grid.Column="1" Text="{Binding Path=Genre}" />
        <TextBox Grid.Row="3" Grid.Column="1" Text="{Binding Path=Type}" />
    </Grid>
    <Button Name="cmdAddMedia" Grid.Row="1" Click="cmdAddMedia_Click" Height="45" Margin="0,0,0,2" Grid.RowSpan="2" VerticalAlignment="Bottom">Add Item</Button>
</Grid>

然后这里是主窗口的C#代码:

public partial class MainWindow : Window
{
    public MultiMediaList MyData { get; set; }
    public void AddStuff()
    {
        MyData.Add(new Multimedia() { Title = "My Way", Artist = "Calvin Harris", Genre = "Pop", Type = Multimedia.MediaType.CD });
        MyData.Add(new Multimedia() { Title = "Inglorious Bastards", Artist = "Quentin Tarantino", Genre = "Violence", Type = Multimedia.MediaType.DVD });
    }
    public MainWindow()
    {
        MyData = new MultiMediaList();
        AddStuff();
        InitializeComponent();
        DataContext = this;            
    }
...
}

最后是 Multimedia 类和 MultiMediaList 类:

public class Multimedia : INotifyPropertyChanged
{
    public enum MediaType { CD, DVD };

    private string _title;
    private string _artist;
    private string _genre;
    private MediaType _type;

    public string Title
    {
        get { return _title; }
        set
        {
            _title = value;
            NotifyPropertyChanged("Title");
        }
    }
    ...
    public override string ToString()
    {
        return _title + " - " + _artist + " [" + _genre + "] - " + getTypeString();
    }

    private string getTypeString()
    {
       if(Type == MediaType.CD) { return "CD"; }
        else { return "DVD"; }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public void NotifyPropertyChanged(string name)
    {
        if (PropertyChanged != null)
        {
             PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
    }
}

MultimediaList 只是一个继承自 ObservableCollection 的空类

public class MultiMediaList: ObservableCollection<Multimedia>
{

}

如果你需要我也可以上传完整代码

希望你能帮助我并告诉我我做错了什么。

【问题讨论】:

  • 有点像duplicate
  • 就是这样,感谢您的帮助!
  • 作为说明,在调用 PropertyChanged 之前不要检查if (PropertyChanged != null),最好写PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); 更短更安全。
  • @Clemens 嗨,你能告诉我为什么它更安全或参考文档
  • 它可能会在 检查 null 之后更改值。

标签: c# wpf data-binding


【解决方案1】:

显然,您希望 ListBox 自动调用 Multimedia 对象的 ToString() 方法,只要它的属性发生更改。事实并非如此。

不要依赖 ToString,而是为 ListBox 声明一个适当的 ItemTemplate:

<ListBox Name="mediaListBox" ItemsSource="{Binding MyData}" Grid.Row="0">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock>
                <Run Text="{Binding Title}"/>
                <Run Text="-"/>
                <Run Text="{Binding Artist}"/>
                <Run Text="["/><Run Text="{Binding Genre}"/><Run Text="]"/>
                <Run Text="{Binding Type}"/>
            </TextBlock>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

TextBlock 可能写得更短:

<TextBlock>
    <Run Text="{Binding Title}"/> - <Run Text="{Binding Artist}"/> [<Run Text="{Binding Genre}"/>] <Run Text="{Binding Type}"/>
</TextBlock>

【讨论】:

  • 成功了,谢谢!有没有办法强制调用 ToString 方法?
  • 不是一个优雅的。作为替代方案,您可以为字符串表示添加另一个属性,例如DisplayText 并在任何其他属性发生更改时始终调用 NotifyPropertyChanged(nameof(DisplayText))。然后,您可以简单地在 ListBox 上设置 DisplayMemberPath="DisplayText",而不是 ItemTemplate。
猜你喜欢
  • 1970-01-01
  • 2011-07-14
  • 1970-01-01
  • 1970-01-01
  • 2010-12-26
  • 2010-11-06
  • 1970-01-01
  • 2010-09-20
  • 1970-01-01
相关资源
最近更新 更多