2016-09-12 7 views
0

Ich habe ein ObservableCollection<UsageItem> MyItems;:beobachtbare Sammlung Ausgabe in List-Box mit DisplayMemberPath

EDIT:

public class UsageItem : INotifyPropertyChanged 
{ 
    string _Name; 
    public string Name 
    { 
     get 
     { 
      return _Name; 
     } 
     set 
     { 
      if (_Name != value) 
      { 
       _Name = value; 
       RaisePropertyChanged("Name"); 
      } 
     } 
    } 

    int _ChargesLeft; 
    public int ChargesLeft 
    { 
     get 
     { 
      return _ChargesLeft; 
     } 
     protected set 
     { 
      if (_ChargesLeft != value) 
      { 
       _ChargesLeft = value; 
       RaisePropertyChanged("ChargesLeft"); 
      } 
     } 
    } 
    public event PropertyChangedEventHandler PropertyChanged; 
     protected void RaisePropertyChanged(string prop) 
     { 
      if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(prop)); } 
     } 
    public Consummable(string name, int charges) 
    { 
     this.Name = name; 
     this.ChargesLeft = charges; 
    } 


    public override string DisplayName 
    { 
     get 
     { 
      if (ChargesLeft > 1) 
      { 
       return Name + " " + ChargesLeft + "charges"; 
      } 
      else 
      { 
       return Name + " " + ChargesLeft + "charge"; 
      } 
     } 
    } 
    public override void use(Hero hero) 
    { 
     if(this.ChargesLeft >= 1) 
     { 
      this.ChargesLeft--; 
     }else{ 
     //Will remove this UsageItem from my ObservableCollection 
     ... 
     } 
    } 

} 

Ich habe meine Collection an ein ListBox gebunden:

<ListBox x:Name="listBoxBackPack" ItemsSource="{Binding MyItems}" SelectedItem="{Binding SelectedItem}" DisplayMemberPath="DisplayName"/> 

Ich habe ein Knopf, dass, wenn geklickt wird, rufen Sie die use Funktion auf meinem SelectedItem, es Verringert den Wert meines ChargesLeft-Felds oder entfernt das Objekt.

Wenn ich auf die Schaltfläche klicke, während mein ChargesLeft-Wert < = 1 ist, wird mein Artikel aus meiner Sammlung entfernt und meine ListBox wird wie erwartet aktualisiert, kein Problem.
Aber wenn ich ein Element mit einem ChargesLeft> = 1 verwende, dann werde ich mein Feld verkleinern und so in der Folge meinen DisplayName ändern.
Als ich noch meine Sammlung ändere, würde ich erwarten, ein CollectionChanged Event zu feuern und meine ListBox zu aktualisieren und die neue DisplayValue des Artikels anzuzeigen, aber es passiert nicht, die ListBox weiterhin die alte DisplayValue anzeigen.
In diesem Moment, wenn ich manuell eine Listbox.Items.Refresh() (Binded es auf einer Schaltfläche zum Testen) wird es aktualisiert und korrekt angezeigt, das Recht DisplayValue, aber ich kann diese Funktion nicht von meinem ViewModel aufrufen, da es keine Kenntnis von meinem ListBox hat

Wie kann ich die Aktualisierung meiner ListBox automatisch erzwingen, wenn ich ein Element ändere?

+1

implementieren 'INotifyPropertyChanged' in' UsageItem' (https://msdn.microsoft.com/library/ms743695(v=vs.110).aspx) – ASh

Antwort

2

CollectionChanged wird ausgelöst, wenn Sie ein Element hinzufügen oder löschen oder die gesamte Sammlung löschen. Ihre UsageItem Klasse muss INotifyPropertyChanged selbst implementieren, um Änderungen in Sammlungselementen zu verfolgen.

https://msdn.microsoft.com/en-us/library/ms668604(v=vs.110).aspx

Hinweis

vollständig Um die Übertragung von Datenwerten aus der Bindung Quellenobjekte verbindliche Ziele zu unterstützen, jedes Objekt in Ihrer Sammlung, die bindungsfähigen Eigenschaften unterstützt, muss eine entsprechende Eigenschaft geändert Benachrichtigungsmechanismus wie die Umsetzung INotifyPropertyChanged-Schnittstelle.

aktualisieren ein funktionsfähiges Beispiel anzeigen (I verwendet Prism, aber das spielt keine Rolle):

UsageItem.cs:

public class UsageItem : INotifyPropertyChanged 
{ 
    string _Name; 
    public string Name 
    { 
     get 
     { 
      return _Name; 
     } 
     set 
     { 
      if (_Name != value) 
      { 
       _Name = value; 
       RaisePropertyChanged("Name"); 
       RaisePropertyChanged("DisplayName"); 
      } 
     } 
    } 

    int _ChargesLeft; 
    public int ChargesLeft 
    { 
     get 
     { 
      return _ChargesLeft; 
     } 
     set 
     { 
      if (_ChargesLeft != value) 
      { 
       _ChargesLeft = value; 
       RaisePropertyChanged("ChargesLeft"); 
       RaisePropertyChanged("DisplayName"); 
      } 
     } 
    } 
    public event PropertyChangedEventHandler PropertyChanged; 
    protected void RaisePropertyChanged(string prop) 
    { 
     if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(prop)); } 
    } 
    public UsageItem(string name, int charges) 
    { 
     this.Name = name; 
     this.ChargesLeft = charges; 
    } 


    public string DisplayName 
    { 
     get 
     { 
      if (ChargesLeft > 1) 
      { 
       return Name + " " + ChargesLeft + "charges"; 
      } 
      else 
      { 
       return Name + " " + ChargesLeft + "charge"; 
      } 
     } 
    } 
} 

MainViewModel:

public class MainWindowViewModel : BindableBase 
{ 
    private string _title = "Prism Unity Application"; 
    public string Title 
    { 
     get { return _title; } 
     set { SetProperty(ref _title, value); } 
    } 

    public MainWindowViewModel() 
    { 
     Items = new ObservableCollection<UsageItem>(); 
     Items.Add(new UsageItem("Bob", 1)); 
     Items.Add(new UsageItem("Bill", 2)); 
     Items.Add(new UsageItem("Joe", 3)); 

     CurrentItem = Items[0]; 

     UseCommand = new DelegateCommand(Use); 
    } 

    public ObservableCollection<UsageItem> Items { get; private set; } 

    private UsageItem _currentItem; 
    public UsageItem CurrentItem 
    { 
     get { return _currentItem; } 
     set { SetProperty(ref _currentItem, value); } 
    } 

    public DelegateCommand UseCommand { get; private set; } 
    private void Use() 
    { 
     if (CurrentItem.ChargesLeft >= 1) 
     { 
      CurrentItem.ChargesLeft--; 
     } 
     else 
     { 
      //Will remove this UsageItem from my ObservableCollection 
      Items.Remove(CurrentItem); 
      CurrentItem = Items[0]; 
     } 
    } 
} 

MainWindow.xaml:

<Window x:Class="UsageLeft.Views.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:prism="http://prismlibrary.com/" 
    Title="{Binding Title}" 
    Width="525" 
    Height="350" 
    prism:ViewModelLocator.AutoWireViewModel="True"> 
<StackPanel> 
    <ListBox ItemsSource="{Binding Items}" SelectedItem="{Binding CurrentItem}"> 
     <ListBox.ItemTemplate> 
      <DataTemplate> 
       <TextBlock Text="{Binding DisplayName}" /> 
      </DataTemplate> 
     </ListBox.ItemTemplate> 
    </ListBox> 
    <Button Command="{Binding UseCommand}" Content="Use" /> 
</StackPanel> 
</Window> 
+0

Ich habe gerade 'INotifyPropertyChanged' implementiert (siehe Edit), beobachte aber immer noch das gleiche Verhalten. Ich kann das PropertyEvent Feuer mit ChargesLeft als Parameter sehen, aber die 'ListBox' wird immer noch nicht aktualisiert, wenn ich es manuell mache – Belterius

+0

@Belterius Ihr Code kann offensichtlich nicht funktionieren, wie oben gezeigt, der Konstruktor hat einen anderen Namen als eine Klasse Die Override-Methoden implizieren, dass es sich um eine Unterklasse handelt, und die 'use'-Methode gehört eindeutig nicht zur Klasse. – mechanic

+3

@Belterius Scheint so, als müssten Sie 'RaisePropertyChanged (" DisplayName ") hinzufügen;' ruft Setter aller Eigenschaften auf, die DisplayName ändern. Siehe die aktualisierte Antwort. – mechanic

Verwandte Themen