项目更改时更新WPF列表

Ben*_*jol 12 .net wpf listbox

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

现在,当我更改影响ToString的属性时,我想让ListBox更新.

  1. 我该怎么做'快而脏'(如重画).
  2. 依赖属性是否可以继续?
  3. 是否值得/总是可取的,为我的FooBars创建一个wpf包装类?

谢谢...

Dre*_*kes 13

您的类型应该实现,INotifyPropertyChanged以便集合可以检测更改.正如萨姆所说,string.Empty作为论点传递.

需要将ListBox数据源设置为提供更改通知的集合.这是通过INotifyCollectionChanged接口(或不那么WPF IBindingList接口)完成的.

当然,INotifyCollectionChanged只要其中一个成员INotifyPropertyChanged项触发其事件,您就需要触发该接口.值得庆幸的是,框架中有一些类型可以为您提供此逻辑.可能是最合适的一个ObservableCollection<T>.如果您绑定ListBox到a,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>
Run Code Online (Sandbox Code Playgroud)

通过这种方式,您可以在XAML中控制对象所在的表示形式.

编辑1我注意到您的评论,您正在使用该ListBox.Items集合作为您的收藏.这不会做必需的绑定.你最好做以下事情:

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

_listBox.ItemsSource = collection;
Run Code Online (Sandbox Code Playgroud)

我没有检查编译准确性的代码,但你得到了要点.

编辑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));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)


Jar*_*Par 5

此处正确的解决方案是为 ListBox IetmsSource 属性使用ObservableCollection<>。WPF 将自动检测此集合内容中的任何更改,并强制相应的 ListBox 更新以反映更改。

您可能需要阅读这篇 MSDN 文章以获取更多信息。写它是为了专门解释如何处理这种情况

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