2016-04-16 8 views
2

Ich ein benutzerdefiniertes Steuerelement in WPF erstellen. Ich binde einen List<IMyInterface> an einen dependency property. Dies wiederum bindet wieder an eine ListBox, die alle Elemente wie erwartet zeigt.Binding List to Textbox wird nicht aktualisiert, wenn ObservableCollection

Ich möchte jetzt 1 Element aus dieser Liste an eine Textblock binden, also binde ich die gesamte Liste an die textblock. Ich habe eine converter in diesem, die das einzelne Element extrahiert, das ich will.

Es hat funktioniert gut, aber für ein paar Gründe, ich will ObservableCollection statt List

Seltsamer verwenden, wenn ich einen Wert in meinem ObservabaleCollection zur Laufzeit ändern, wird der Wert in dem ListBox (Erfolg) gezeigt aber nicht in meinem textblock. Die converter ist nicht einmal getroffen!

public MainWindow() 
    { 
     InitializeComponent(); 
     this.DataContext = this; 
     this.Errors = new ObservableCollection<IEventDetail>(); 
     this.Errors.CollectionChanged += Errors_CollectionChanged; 
     var bw = new BackgroundWorker(); 
     bw.DoWork += ((o, e) => 
     { 
      System.Threading.Thread.Sleep(1500); 
      Dispatcher.Invoke(() => 
      { 
       this.Errors.Add(new MyEvents("example of some detail", "Failed title")); 
      }); 

      System.Threading.Thread.Sleep(2500); 

      Dispatcher.Invoke(() => 
      { 
       this.Errors.Add(new MyEvents("Another example", "Failed title 2")); 
      }); 
     }); 
     bw.RunWorkerAsync();//background worker for testing/debugging only 
    } 

    private void Errors_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) 
    { 
     OnPropertyChanged("Errors"); 
    } 

    private ObservableCollection<IEventDetail> _errors; 
    public ObservableCollection<IEventDetail> Errors 
    { 
     get 
     { 
      return this._errors; 
     } 
     set 
     { 
      this._errors = value; 
      OnPropertyChanged("Errors"); 
     } 
    } 


    public event PropertyChangedEventHandler PropertyChanged; 
    public void OnPropertyChanged(string propertyName) 
    { 
     if (PropertyChanged == null) 
      return; 

     PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
    } 

Und der XAML ist einfach

<local:Notify Events="{Binding Errors}" DockPanel.Dock="Right"/> 

Wie Sie sehen können, habe ich versucht, die CollectionChanged Ereignis zu verwenden, um dann Feuer zu zwingen die INotifyPropertyChanged, aber es Brennen in meinem Converter noch die ListBox ist Aktualisierung fein (so die Bindung ist in Ordnung, ich weiß)

Dies ist die

xAML ist

Muss ich etwas anderes machen?

+0

Das Problem muss auf xaml sein, onopropertychange ist implizit in observableCollection. (Kannst du den XAML posten?) Versuch, explicti Zwei-Wege-Bindung und UpdataSourceTrigger = PropertyChanged – Xilmiki

+0

@ Xilmiki, danke, aber die Bindung ** ist ** Arbeiten an der "ListBox", aber nicht die "Textblock".Also bin ich mir nicht sicher, warum ich 2-Wege-Bindung oder sogar verwenden sollte UpdateSourceTrigger – Dave

+0

Plese versuchen, explizite Zwei-Wege-Bindung und UpdataSourceTrigger = PropertyChanged in TextBox-Bindung, ich hatte das gleiche Problem auf meinem WPF-Projekt. – Xilmiki

Antwort

1

Wie in den Kommentaren erwähnt TextBlock es nur Events Eigenschaftsänderung gebunden (nicht seine Artikel) so wird es nicht auslösen, wenn nicht neue Instanz der Sammlung erstellt wird. Reagieren auf INotifyCollectionChanged ist charakteristisch für ItemsSource Eigenschaft.

Lösung 1

alles lassen, wie es im Moment ist nur TextBlock

<TextBlock Text="{Binding ...}" x:Name="myTextBlock"/> 

und abonnieren Sie CollectionChanged Ereignis einen Namen in Ihrem UserControl geben, wo Sie manuell verbindliches Ziel zwingen zu aktualisieren

public partial class MyUserControl : UserControl 
{ 
    public static readonly DependencyProperty EventsProperty = 
           DependencyProperty.Register("Events", 
            typeof(IEnumerable), 
            typeof(MyUserControl), 
            new PropertyMetadata(EventsPropertyChanged)); 

    private static void EventsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     ((MyUserControl)d).EventsPropertyChanged(e); 
    } 

    private void EventsPropertyChanged(DependencyPropertyChangedEventArgs args) 
    { 
     var newCollection = args.NewValue as INotifyCollectionChanged; 
     if (newCollection != null) 
      newCollection.CollectionChanged += (s, e) => myTextBlock.GetBindingExpression(TextBlock.TextProperty).UpdateTarget(); 
    } 

    public IEnumerable Events 
    { 
     get { return (IEnumerable)GetValue(EventsProperty); } 
     set { SetValue(EventsProperty, value); } 
    } 

} 

Lösung 2

Ihre eigene Sammlung Klasse Erstellen von ObservableCollection<T> mit benutzerdefinierter Eigenschaft geerbt, das tun würde, was Ihr Konverter

public class MyObservableCollection<T> : ObservableCollection<T> 
{ 
    private string _convertedText; 

    protected override void OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e) 
    { 
     base.OnCollectionChanged(e); 
     this.ConvertedText = ...; // <- do here what your IValueConverter does 
    } 

    public string ConvertedText 
    { 
     get { return _convertedText; } 
     private set 
     { 
      _convertedText = value; 
      OnPropertyChanged(new PropertyChangedEventArgs("ConvertedText")); 
     } 
    } 
} 

tut und bindet TextBlock.Text-Events.ConvertedText Eigenschaft stattdessen ohne Notwendigkeit Konverter

Verwandte Themen