ObservableCollection中的更改不会更新ListView [英] Changes in ObservableCollection do not update ListView

查看:1740
本文介绍了ObservableCollection中的更改不会更新ListView的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经在板上阅读了所有相关文章,但是我仍然无法解决我将ObservableCollection绑定到ListView时遇到的问题。

I have been reading all the related articles here in the board but I still can't solve my problem that I have when binding an ObservableCollection to a ListView.

我有一个基本包装一个字符串的CLogEntry模型类。

I have a CLogEntry model class which basically wraps a string.

/// Model of LogEntry
public class CLogEntry:INotifyPropertyChanged
{
    /// Fields
    private string _logEntry;

    /// Property
    public string LogEntry
    {
        get { return _logEntry; }

        set
        {
            _logEntry = value;
            RaisePropertyChanged("LogEntry");
        }
    }

    /// PropertyChanged event handler
    public event PropertyChangedEventHandler PropertyChanged;

    /// Constructor
    public CLogEntry(string logEntry)
    {
        this.LogEntry = logEntry;
    }

    /// Property changed Notification        
    public void RaisePropertyChanged(string propertyName)
    {
        // take a copy to prevent thread issues
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

在我的ViewModel中我有一个ObservableCollection保存我的CLogEntry对象以及相应的公共属性。

In my ViewModel I have an ObservableCollection that holds my CLogEntry objects as well as the corresponding public property for it.

class CLoggerViewModel : INotifyPropertyChanged
{
    /// Memory Appender object
    private CMemoryAppender _memoryAppender;
    /// ObservableCollection for LogEntries
    private ObservableCollection<CLogEntry> _logEntries;

    /// Property to expose ObservableCollection for UI
    public ObservableCollection<CLogEntry> LogEntries
    {
       get { return _logEntries; }
    }

    /// Event for PropertyChanged Notification
    public event PropertyChangedEventHandler PropertyChanged;

    /// Constructor of viewModel
    public CLoggerViewModel()
    {
        this._logEntries = new ObservableCollection<CLogEntry>();
        this._memoryAppender = new CMemoryAppender();
        this._memoryAppender.PropertyChanged += new PropertyChangedEventHandler(OnMemoryAppenderPropertyChanged);
        this._memoryAppender.LogContentChanged += new LoggingEventHandler(OnLogContentChanged);
    }

    /// Update collection
    public void OnLogContentChanged(object sender, LoggingEventArgs e)
    {
        ///  Here i add LogEntries event based to my collection.
        ///  For simplicity i just used a temporarly string here.
        string[] tmpString = { "A", "B", "C", "D" };

        foreach (string s in tmpString)
        {
            this.LogEntries.Add(new CLogEntry(s));
        }
    }

    /// Any of the properties of the MemoryAppender objects has changed
    private void OnMemoryAppenderPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        this.RaisePropertyChanged(e.PropertyName);
    }

    /// PropertyChanged EventHandler
    public void RaisePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

我的ListView的XAML代码如下:

My XAML code for the ListView is the following:

<ListView x:Name="lstLogs" DataContext ="{Binding LoggerViewModel}"  ItemsSource="{Binding LogEntries}" Margin="5,5,5,5" Grid.Column="1" Grid.Row="0">
    <ListView.View>
        <GridView x:Name="grdLogs">
            <GridViewColumn Header="Log Entry"  DisplayMemberBinding="{Binding Path=LogEntries}"/>
        </GridView>
    </ListView.View>
</ListView>

我的问题是列表不显示任何数据。
但是当我调试代码时,我可以看到我的ObservableCollection的属性被调用,并且我的集合包含我添加的所有LogEntries。
所以我假设CollectionChanged事件被触发,UI正在调用我的LogEntries属性。
但我不明白为什么ListView不显示任何数据。

My Problem is that the list does not show any data. But when I debug the code I can see that my property for the ObservableCollection gets called and that my collection holds all the LogEntries that I add. So I assume that the CollectionChanged event gets fired and the UI is calling my LogEntries property. But I don't understand why the ListView does not show any data.

我的XAML代码是否有问题,或者是模型中的问题, /或ViewModel?

Is there a problem with my XAML code or is it a problem in model and/or ViewModel?

编辑:

最后,问题是一个线程问题。
由于ObervableCollection是由UI线程创建的,如果另一个线程正在添加/处理集合,它将抛出异常。
为了摆脱这个问题,我发现以下解决方案实现了一个异步ObservableCollection。

Finally the problem was a threading issue. Since the ObervableCollection is created by the UI thread it throws an exception if another thread is adding/manipulating the collection. To get rid of this problem i found the following solution that implements an Asynchronous ObservableCollection.

以下链接帮助我得到它的工作:
< a href =http://stackoverflow.com/questions/2104614/updating-an-observablecollection-in-a-separate-thread> Stackoverflow

Following links helped me to get it working: Stackoverflow Implementing Async ObservableCollection

推荐答案

如果 DataContext 是您的viewmodel(CLoggerViewModel),则Itemssource绑定应为:

if the DataContext is your viewmodel (CLoggerViewModel) then the Itemssource binding should be:

  <ListView ItemsSource="{Binding LogEntries}" Margin="5,5,5,5" Grid.Column="1" Grid.Row="0">

并且您的LogEntry的绑定表达式应该只是{Binding LogEntry}

and the binding expression to your LogEntry should simply be {Binding LogEntry}

  <GridViewColumn Header="Log Entry"  DisplayMemberBinding="{Binding Path=LogEntry}"/>

编辑:


  • 在XAML中忘记智能感知!

  • 您的ListView ItemsSource必须绑定到Viewmodel中的Property LogEntries CLoggerViewModel

  • GridViewColumn DisplayMemberBinding必须绑定到您的类CLogEntry中的Property LogEntry

编辑:最新更新

DataContext ={Binding LoggerViewModel - >那是什么?这意味着您需要在当前的Datacontext上使用名为LoggerViewModel的公共属性。我不认为这是你想要的。您的Viewmodel代码看起来不错,但问题是您的XAML和设置您的Datacontext。所以请发布您设置DataContext的代码。

DataContext ="{Binding LoggerViewModel}" --> What is that? this means you need a public property called LoggerViewModel on your current Datacontext. i dont think thats what you want. your Viewmodel code looks ok, but the problem is your XAML and setting your Datacontext. so pls post the code where you set the DataContext.

编辑:工作代码

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<ListView ItemsSource="{Binding LogEntries}">
    <ListView.View>
        <GridView >
            <GridViewColumn Header="Log Entry"  DisplayMemberBinding="{Binding Path=LogEntry}"/>
        </GridView>
    </ListView.View>
</ListView>
</Window>

cs

public partial class MainWindow : Window
{
    private CLoggerViewModel _vm = new CLoggerViewModel();
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = _vm;
    }
}

public class CLogEntry : INotifyPropertyChanged
{
    /// Fields
    private string _logEntry;

    /// Property
    public string LogEntry
    {
        get { return _logEntry; }

        set
        {
            _logEntry = value;
            RaisePropertyChanged("LogEntry");
        }
    }

    /// PropertyChanged event handler
    public event PropertyChangedEventHandler PropertyChanged;

    /// Constructor
    public CLogEntry(string logEntry)
    {
        this.LogEntry = logEntry;
    }

    /// Property changed Notification        
    public void RaisePropertyChanged(string propertyName)
    {
        // take a copy to prevent thread issues
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

class CLoggerViewModel : INotifyPropertyChanged
{
    /// Memory Appender object
    //private CMemoryAppender _memoryAppender;
    /// ObservableCollection for LogEntries
    private ObservableCollection<CLogEntry> _logEntries;

    /// Property to expose ObservableCollection for UI
    public ObservableCollection<CLogEntry> LogEntries
    {
        get { return _logEntries; }
    }

    /// Event for PropertyChanged Notification
    public event PropertyChangedEventHandler PropertyChanged;

    /// Constructor of viewModel
    public CLoggerViewModel()
    {
        this._logEntries = new ObservableCollection<CLogEntry>();
        //dunno what CMemoryAppender is
        //this._memoryAppender = new CMemoryAppender();
        //this._memoryAppender.PropertyChanged += new PropertyChangedEventHandler(OnMemoryAppenderPropertyChanged);
        //this._memoryAppender.LogContentChanged += new LoggingEventHandler(OnLogContentChanged);

        //thats why i fill my collection here
        string[] tmpString = { "A", "B", "C", "D" };

        foreach (string s in tmpString)
        {
            this.LogEntries.Add(new CLogEntry(s));
        }
    }
    /// Any of the properties of the MemoryAppender objects has changed
    private void OnMemoryAppenderPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        this.RaisePropertyChanged(e.PropertyName);
    }

    /// PropertyChanged EventHandler
    public void RaisePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

这篇关于ObservableCollection中的更改不会更新ListView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆