【问题标题】:ListBox bound to ObservableCollection doesn't update绑定到 ObservableCollection 的 ListBox 不会更新
【发布时间】:2012-02-29 13:44:30
【问题描述】:

我无法让 ListBox 绑定按预期工作。我目前正在尝试将 ListBox 绑定到单例公开的 ObservableCollection 项目。这些项目本身就是一个单独的类。目前,我是这样绑定的:

<Window x:Class="toxySharp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:classes="clr-namespace:MyApplication.Classes"
        Title="MainWindow" Height="325" Width="400"
        DataContext="{Binding Source={x:Static local:SingletonClass.Instance}}">

        <Grid x:Name="LayoutRoot">
            <ListBox x:Name="lstMyList" ItemsSource="{Binding Path=Objects, Mode=TwoWay}" DisplayMemberPath="Name" />
        </Grid>
</Window>

我的单例是这样的基本实现:

public class SomeObject : INotifyPropertyChanged
{
    private Int32 m_vId;
    private String m_vName;

    public SomeObject() { }

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged(String propName)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
    }

    public Int32 Id
    {
        get { return this.m_vId; }
        set { this.m_vId = value; NotifyPropertyChanged("Id"); }
    }

    public String Name
    {
        get { return this.m_vName; }
        set { this.m_vName = value; NotifyPropertyChanged("Name"); }
    }
}

public class SingletonClass : INotifyPropertyChanged
{
    private static SingletonClass m_vInstance;
    private ObservableCollection<SomeObject> m_vObjects;

    private SingletonClass()
    {
        this.m_vObjects = new ObservableCollection<SomeObject>();
        for (int x = 0; x < 255; x++)
            this.m_vObjects.Add(new SomeObject() { Id = x, Name = String.Format("{0} - new object", x) });
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged(String propName)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
    }

    public static SingletonClass Instance
    {
        get
        {
            if (m_vInstance == null)
                m_vInstance = new SingletonClass();
            return m_vInstance;
        }
    }

    public ObservableCollection<SomeObject> Objects
    {
        get { return this.m_vObjects; }
        set { this.m_vObjects = value; NotifyPropertyChanged("Objects"); }
    }
}

目前,绑定在启动时起作用。应用程序将绑定并正确显示每个对象的名称。例如,这是一个执行相同实现的测试应用程序:

在我的主要实际应用程序中,我调用了异步方法(套接字内容 BeginConnect、BeginSend 等),这些方法使用可以更新集合的回调。 (这是一个玩家列表,所以当收到某些数据包时,列表会更新他们的数据。)

我的问题是,当集合在其中一个异步回调中更新时,它不会在列表中更新。集合数据已正确更新,在主代码中的任何位置设置中断显示集合正在更新,但列表框永远不会更新以反映更改。所以不管怎样,它只会说同样的话。

我是不是忽略了什么?

我也尝试使用 CollectionViewSource 来允许过滤,但也有同样的问题。

== 编辑 ==

我发现单例中的问题在于集合的初始化方式。在初始化集合时,我需要使用公开的属性来允许它更新 UI,而不是使用内部副本成员。

所以使用以下修复它:

private SingletonClass()
{
    this.Objects = new ObservableCollection<SomeObject>();
    for (int x = 0; x < 255; x++)
        this.Objects.Add(new SomeObject() { Id = x, Name = String.Format("{0} - new object", x) });
}

但是,既然列表绑定有效,我希望能够根据对象类中的另一个属性对其进行过滤。 (在示例 SomeObject 中)。我有一个布尔值说明对象是否处于活动状态。尝试绑定到 CollectionViewSource 会导致我回到不更新的问题。那么有没有办法手动过滤并保持 ui 更新?

【问题讨论】:

    标签: c# wpf binding listbox observablecollection


    【解决方案1】:

    UpdateSourceTrigger=缺少PropertyChanged

    <ListBox x:Name="lstMyList" ItemsSource="{Binding Path=Objects,UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" DisplayMemberPath="Name" />
    

    【讨论】:

    • 这根本不做任何事情,ItemsSource 在目标上永远不会改变,在任何情况下它都不会传播回源。
    • 如果我正确理解了 OP,那么它是正在更新的源,但视图没有看到它。需要更新sourcetrigger=propertychanged 来修复它。如果它什么都不做,那么让我知道你对“来源”的定义是什么。在我看来,这意味着视图模型上的 observablecollection
    • 不,UpdateSourceTrigger 另辟蹊径,例如在TextBox 中,当有人输入文本时,它会确定Text 绑定到的源是否应在每次击键时更新。 ItemsControls 不要更改 ItemsSource 属性,也不能通过用户输入更改,UpdateSourceTrigger 永远不会做任何事情。
    【解决方案2】:

    我的问题是当集合在其中一个异步中更新时 回调它不会在列表中更新。

    这就是问题所在! Observable 集合不是线程安全的。你需要这样做。

    没有TwoWay 绑定模式或UpdateSourceTrigger=PropertyChanged 在这种情况下会有所帮助,因为问题在于代码中的多线程...

    为了您的方便,使用这个线程安全和更快的可观察集合的自定义实现...

    Fast performing and thread safe observable collection

    INotifyPropertyChanged接口而言,其'PropertyChangedevent is automatically dispatched to the UI thread. So any multithreaded context updating the properties of a class that implementsINotifyPropertyChanged`将更新GUI。

    如果这有帮助,请告诉我,

    【讨论】:

    • 没有线程问题,我确保回调中的任何内容都被调用到主线程上,以确保不会发生线程问题。
    • 编辑了主要问题,我找到了更新问题的原因。但现在的问题是如何对其进行排序,因为绑定到 CollectionViewSource 会再次导致不更新问题。
    • 你可以将集合视图 (CollectionViewSource.DefaultView) 绑定到列表框而不是集合本身吗?
    • 我看不到在 Xaml 中执行此操作的方法,因为我不想为此依赖代码隐藏。你有这方面的例子吗?
    • 可能不是最好的解决方案,但我放弃了尝试使用 CollectionViewSource。相反,我只是定义了一个自定义模板并根据我想与过滤一起使用的 Active 属性设置项目的可见性。这是按预期工作的,但我希望我能做到这一点,以处理暴露给我的适当事物。
    猜你喜欢
    • 1970-01-01
    • 2011-10-25
    • 2018-09-11
    • 2011-08-16
    • 2012-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多