项目更改时更新 WPF 列表

问题描述 投票:0回答:5

我有一个 WPF

ListBox
,并且我添加了一些 'FooBar' 对象作为项目(通过代码)。
FooBars
不是 WPF 对象,只是带有覆盖
ToString()
函数的愚蠢类。

现在,当我更改影响

ToString
的属性时,我希望更新
ListBox

  1. 我怎样才能做到这一点“又快又脏”(比如重新粉刷)。
  2. 依赖属性是继续下去的方法吗?
  3. 为我的
    FooBars
    创建一个WPF包装类是否值得/总是明智的?
.net wpf listbox
5个回答
14
投票

您的类型应该实现

INotifyPropertyChanged
,以便集合可以检测到更改。 正如 Sam 所说,传递
string.Empty
作为参数。

需要让

ListBox
的数据源是提供更改通知的集合。 这是通过
INotifyCollectionChanged
接口(或不那么 WPF
IBindingList
接口)完成的。

当然,只要成员

INotifyCollectionChanged
项目之一触发其事件,您就需要
INotifyPropertyChanged
接口来触发。 值得庆幸的是,框架中有一些类型可以为您提供这种逻辑。 可能最合适的是
ObservableCollection<T>
。 如果您将
ListBox
绑定到
ObservableCollection<FooBar>
,那么事件链将会自动发生。

相关说明,您不必使用

ToString
方法来让 WPF 以您想要的方式呈现对象。 您可以像这样使用
DataTemplate

<ListBox x:Name="listBox1">
    <ListBox.Resources>
        <DataTemplate DataType="{x:Type local:FooBar}">
            <TextBlock Text="{Binding Path=Property}"/>
        </DataTemplate>
    </ListBox.Resources>
</ListBox>

通过这种方式,您可以在 XAML 中控制对象所属位置的呈现。

编辑1我注意到您的评论,您正在使用

ListBox.Items
集合作为您的集合。 这不会完成所需的绑定。 你最好做这样的事情:

var collection = new ObservableCollection<FooBar>();
collection.Add(fooBar1);

_listBox.ItemsSource = collection;

我还没有检查该代码的编译准确性,但你明白了要点。

编辑2使用我上面给出的

DataTemplate
(我对其进行了编辑以适合您的代码)解决了问题。

似乎很奇怪,触发

PropertyChanged
不会导致列表项更新,但使用
ToString
方法并不是 WPF 的预期工作方式。

使用此 DataTemplate,UI 可以正确绑定到确切的属性。

我不久前在这里问了一个关于在 WPF 绑定中进行字符串格式化的问题。 您可能会发现它很有帮助。

编辑3

我很困惑为什么这仍然不适合你。 这是我正在使用的窗口的完整源代码。 背后代码:

using System.Collections.ObjectModel; using System.ComponentModel; using System.Windows; namespace StackOverflow.ListBoxBindingExample { public partial class Window1 { private readonly FooBar _fooBar; public Window1() { InitializeComponent(); _fooBar = new FooBar("Original value"); listBox1.ItemsSource = new ObservableCollection<FooBar> { _fooBar }; } private void button1_Click(object sender, RoutedEventArgs e) { _fooBar.Property = "Changed value"; } } public sealed class FooBar : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private string m_Property; public FooBar(string initval) { m_Property = initval; } public string Property { get { return m_Property; } set { m_Property = value; OnPropertyChanged("Property"); } } private void OnPropertyChanged(string propertyName) { var handler = PropertyChanged; if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); } } }

XAML:

<Window x:Class="StackOverflow.ListBoxBindingExample.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:StackOverflow.ListBoxBindingExample" Title="Window1" Height="300" Width="300"> <DockPanel LastChildFill="True"> <Button Click="button1_Click" DockPanel.Dock="Top">Click Me!</Button> <ListBox x:Name="listBox1"> <ListBox.Resources> <DataTemplate DataType="{x:Type local:FooBar}"> <TextBlock Text="{Binding Path=Property}"/> </DataTemplate> </ListBox.Resources> </ListBox> </DockPanel> </Window>



5
投票
ObservableCollection<>

。 WPF 将自动检测此集合内容中的任何更改,并强制相应的 ListBox 更新以反映更改。 您可能需要阅读这篇 MSDN 文章以获取更多信息。 编写它是为了专门解释如何处理这种情况

http://msdn.microsoft.com/en-us/magazine/dd252944.aspx?pr=blog


1
投票


1
投票

using System; using System.Collections.Generic; using System.Windows; using System.Windows.Controls; using System.ComponentModel; using System.Collections.ObjectModel; namespace ListboxOfFoobar { /// <summary> /// Interaction logic for Window1.xaml /// </summary> public partial class Window1 : Window { public Window1() { InitializeComponent(); } private void Button_Click(object sender, RoutedEventArgs e) { ObservableCollection<FooBar> all = (ObservableCollection<FooBar>)FindResource("foobars"); all[0].P1 = all[0].P1 + "1"; } } public class FooBar : INotifyPropertyChanged { public FooBar(string a1, string a2, string a3, string a4) { P1 = a1; P2 = a2; P3 = a3; P4 = a4; } public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged(String info) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(info)); } } private String p1; public string P1 { get { return p1; } set { if (value != this.p1) { this.p1 = value; NotifyPropertyChanged("P1"); } } } private String p2; public string P2 { get { return p2; } set { if (value != this.p2) { this.p2 = value; NotifyPropertyChanged("P2"); } } } private String p3; public string P3 { get { return p3; } set { if (value != this.p3) { this.p3 = value; NotifyPropertyChanged("P3"); } } } private String p4; public string P4 { get { return p4; } set { if (value != this.p4) { this.p4 = value; NotifyPropertyChanged("P4"); } } } public string X { get { return "Foooooo"; } } } public class Foos : ObservableCollection<FooBar> { public Foos() { this.Add(new FooBar("a", "b", "c", "d")); this.Add(new FooBar("e", "f", "g", "h")); this.Add(new FooBar("i", "j", "k", "l")); this.Add(new FooBar("m", "n", "o", "p")); } } }

这是 XAML:

<Window x:Class="ListboxOfFoobar.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:ListboxOfFoobar" xmlns:debug="clr-namespace:System.Diagnostics;assembly=System" Title="Window1" Height="300" Width="300" > <Window.Resources> <local:Foos x:Key="foobars" /> <DataTemplate x:Key="itemTemplate"> <StackPanel Orientation="Horizontal"> <TextBlock MinWidth="80" Text="{Binding Path=P1}"/> <TextBlock MinWidth="80" Text="{Binding Path=P2}"/> <TextBlock MinWidth="80" Text="{Binding Path=P3}"/> <TextBlock MinWidth="80" Text="{Binding Path=P4}"/> </StackPanel> </DataTemplate> </Window.Resources> <DockPanel> <ListBox DockPanel.Dock="Top" ItemsSource="{StaticResource foobars}" ItemTemplate="{StaticResource itemTemplate}" Height="229" /> <Button Content="Modify FooBar" Click="Button_Click" DockPanel.Dock="Bottom" /> </DockPanel> </Window>

按下按钮会导致第一个 FooBar 的第一个属性被更新并显示在 ListBox 中。


0
投票

即,如果集合发生更改,与其绑定的任何控件数据都将更新,反之亦然。

© www.soinside.com 2019 - 2024. All rights reserved.