2014-09-09 24 views
5

Tüm ilgili makaleleri tahtada okudum ancak bir ObservableCollection'ı bir ListView'e bağlarken sahip olduğum problemi hala çözemiyorum.GözlemlenebilirKoleksiyondaki Değişiklikler güncelleştirilmez ListView

Temel olarak bir dizeyi saran bir CLogEntry model sınıfım var. benim ViewModel içinde

/// 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)); 
     } 
    } 
} 

benim CLogEntry nesneleri yanı sıra bunun için karşılık gelen kamu malına tutan bir ObservableCollection var.

<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> 

My Problem liste herhangi bir veri göstermiyor olmasıdır:

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 Benim XAML kod şudur. Ancak kodu hata ayıkladığında, ObservableCollection özelliğimin çağrıldığını ve koleksiyonumun eklediğim tüm LogEntries'i tuttuğunu görebiliyorum. Dolayısıyla CollectionChanged olayının tetiklendiğini ve kullanıcı arabiriminin LogEntries özelliğini çağırdığını varsayalım. Ama neden ListView'in herhangi bir veri göstermediğini anlamıyorum.

XAML kodumda bir sorun var mı, yoksa model ve/veya ViewModel'de sorun mu var?

DÜZENLEME:

Nihayet sorun parçacığı konu oldu. ObervableCollection, UI iş parçacığı tarafından oluşturulduğundan, başka bir iş parçacığı koleksiyona ekliyor/işliyorsa bir istisna atar. Bu sorundan kurtulmak için bir Asynchronous ObservableCollection uygulayan aşağıdaki çözümü buldum.

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

ve bağlayıcı ifadesi: Stackoverflow Implementing Async ObservableCollection

+0

? Ve LogEntries özelliğini başlattığınızda? – har07

+0

pls Senkronize Etmek için DataContext ve Binding İfadenizi çalışma zamanında kontrol edin – blindmeis

+0

@blindemeis: Spoof bana şunu söylüyor: DataContext - [Logger.CLoggerViewModel] {Yol = LoggerViewModel}. Ama BindingExpression için emin değilim. Spoof ListView için Binding.XmlNamespaceManager ve BindingGroup özelliklerini buldum. Ancak, her iki özellik de çalışma zamanı boyunca herhangi bir değere sahip değildir. – ck84vi

cevap

1

DataContext sizin ViewModel (CLoggerViewModel) daha sonra bağlayıcı ItemsSource olmalıdır ise:

takiben bağlantılar beni almak o çalışma için yardımcı LogEntry'iniz sadece {Binding LogEntry}

<GridViewColumn Header="Log Entry" DisplayMemberBinding="{Binding Path=LogEntry}"/> 
olmalıdır

DÜZENLEME:

  • XAML IntelliSense unutun! ItemsSource sizin ViewModel CLoggerViewModel
  • GridViewColumn DisplayMemberBinding Mülkiyet LogEntries bağlamak zorunda
  • ListView sınıf CLogEntry içinde Mülkiyet LogEntry için

DÜZENLEMEYİ bağlamak zorunda: En son güncellemeler için

DataContext = "{LoggerViewModel} Bağlama" -> Bu nedir? Bu, geçerli Datacontext'inizde LoggerViewModel adında bir public özelliğine ihtiyacınız olduğu anlamına gelir. Ne istediğini düşünmüyorum. Viewmodel kodunuz iyi görünüyor, ancak sorun XAML'iniz ve Datacontext'inizi ayarlıyor. Yani pls DataContext'i ayarladığınız kodu postalayın.

DÜZENLEME: Çalışma kod

<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 size `DataContext` ayarlamak nasıl

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)); 
     } 
    } 
} 
+0

@blindemeis: Düzenlenmiş yayınımda gösterildiği gibi XAML'yi ipucunuza göre değiştirdim. Ama şimdi benim problemim, koleksiyona nesneleri eklediğim foreach döngü yinelemenin, listeye ilk nesneyi ekledikten sonra durması. Daha önce bu problemi yaşadım ve bir sınıfa dizgeyi silerek çözüldüğünü düşündüm. Bunu zaten bu konuya gönderdim çünkü problemin WPF parçasından kaynaklandığını fark etmedim. http://stackoverflow.com/questions/25722641/add-string-array-to-observablecollectionstring-does-not-work – ck84vi

+0

ItemsSource Binding LoggerViewModel değil LogEntries olmalıdır. – blindmeis

+0

@blindemeis: Sahip olduğum şey -> ItemsSource = "{Binding LogEntries}". Bu yazıyı daha önce güncelledim. Söylediğim gibi. Bunu yaptığımdan beri foreach döngüsüm, ilk nesneyi ekledikten sonra koleksiyona nesne eklemeyi bırakıyor. – ck84vi