2016-10-26 2 views
0

Mein Textblock wird nicht aktualisiert Den Wert aus meinem Modell aktualisieren. Wenn ich den Textblock im ViewModel aktualisiere, funktioniert das so, dass meine Bindungen korrekt zu sein scheinen. Ich glaube, das Problem ist die Art, wie ich es im Model aktualisiere, aber ich bin mir nicht sicher, warum auch meine ObservableCollection nur aktualisiert, weil ich die Werte hin und her gebe, nicht sicher, dass MVVM eine gute Strategie ist.Textblock wird nicht aktualisiert, wenn die Eigenschaft im Modell geändert wurde

XAML Teil:

<Grid> 
    <TextBox x:Name="NewLabelBx" HorizontalAlignment="Left" Height="23" Margin="54,449,0,0" TextWrapping="Wrap" Text="{Binding NewLabel,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="314"/> 
    <Button x:Name="NewLabelBtn" Content="Add Label" HorizontalAlignment="Left" Margin="293,490,0,0" VerticalAlignment="Top" Width="75" RenderTransformOrigin="0.518,-0.709" Command="{Binding Path=NewLabelBtn}" /> 
    <TextBlock x:Name="FilesProcessedBlck" HorizontalAlignment="Left" Margin="54,507,0,0" TextWrapping="Wrap" Text="{Binding FilesProcessedBlck, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" RenderTransformOrigin="-0.7,0.562" Width="65"/> 
</Grid> 

Ansichtsmodell Portion:

public class P4LabelBatteryViewModel : BindableBase 
{ 
    private P4LabelBatteryModel p4LabelBatteryModel = new P4LabelBatteryModel(); 

    public P4LabelBatteryViewModel() 
    { 
     P4LabelBatteryModel p4LabelBatteryModel = new P4LabelBatteryModel(); 

     this.GetBatteryBtn = new DelegateCommand(chooseFile, canChooseFile); 
     this.NewLabelBtn = new DelegateCommand(chooseNewLabel, canNewLabel).ObservesProperty(() => NewLabel); 
     this.FilesProcessedBlck = 2; //this works. 
    } 

    //other code here 

    private void chooseNewLabel() 
    { 
     if (ScriptCollection.Count > 0) 
     { 
      ScriptCollection = P4LabelBatteryModel.TagsFilesModel(NewLabel, ScriptCollection); 
     } 
    } 


    private int _filesProcessedBlck; 
    public int FilesProcessedBlck 
    { 
     get 
     { 
      return _filesProcessedBlck; 
     } 
     set 
     { 
      SetProperty(ref _filesProcessedBlck, value); 
     } 

    } 

    private ObservableCollection<ScriptModel> _scriptCollection = new ObservableCollection<ScriptModel>(); 
    public ObservableCollection<ScriptModel> ScriptCollection 
    { 
     get 
     { 
      return _scriptCollection; 
     } 
     set 
     { 
      SetProperty(ref _scriptCollection, value); 
     } 

    }   

} 

Modell Teil:

class P4LabelBatteryModel 
{ 

    public static ObservableCollection<ScriptModel> TagsFilesModel(string NewLabel, ObservableCollection<ScriptModel> observableCollection) 
    { 
     string newLabel = NewLabel; 
     var scriptsToTagColl = observableCollection; 
     string[] files = null; 

     var _p4LabelBatteryViewModel = new P4LabelBatteryViewModel(); 
     _p4LabelBatteryViewModel.FilesProcessedBlck++; //xaml is never updated with this value. 

     //This will generate an IPC when returned 
     ObservableCollection<ScriptModel> newCollection = new ObservableCollection<ScriptModel>(); 

     //code here that modifies newCollection xaml updates when this returns, _p4LabelBatteryViewModel.FilesProcessedBlck++; does not. 

     return newCollection; 
    } 
} 

Wenn ich den Debugger ausführen kann ich sehen, die P4LabelBatteryViewModel.FilesProcessedBlck geändert wird, aber Der XAML wird nicht aktualisiert.

+0

Sieht aus wie ein Problem mit Ihrem '.DataContext'. Es sieht so aus, als ob Sie es nicht richtig zugeordnet haben, also zeigt Ihr TextBlock auf eine Instanz von 'P4LabelBatteryViewModel', während Sie eine zweite Instanz in Ihrem' ObservableCollection' Code erstellen. – Rachel

Antwort

1
var _p4LabelBatteryViewModel = new P4LabelBatteryViewModel(); 
    _p4LabelBatteryViewModel.FilesProcessedBlck++; //xaml is never updated with this value. 

OK, so dass Ihr XAML muss eine Kopie des Viewmodels hat, wenn die TextBlock jemals zeigt, was Sie in erster Linie erwarten. Aber dann erstellen Sie in dieser Methode eine neue Instanz derselben Viewmodel-Klasse, legen eine Eigenschaft fest und machen dann nichts anderes mehr. Es geht aus dem Rahmen und der Müllsammler isst es schließlich. Es war nie der DataContext irgendeiner Ansicht, nirgends, also hat es natürlich keine Auswirkungen auf die Benutzeroberfläche.

_p4LabelBatteryViewModel ist eine lokale Variable. Niemand außerhalb dieser Methode sieht es jemals oder weiß sogar, dass es existiert. Wenn Sie die Kopie des Ansichtsmodells ändern möchten, das tatsächlich auf der Benutzeroberfläche angezeigt wird, müssen Sie diese Instanz davon ändern. Stellen Sie lokale Variablen auch nicht mit _ voran. Per Konvention weist ein führender Unterstrich auf ein privates Feld hin, das zu einer Klasse gehört. Es ist am besten, bei dieser Konvention zu bleiben, um Verwirrung zu vermeiden.

Das Viewmodel sollte seine eigene FilesProcessedBlck Eigenschaft aktualisieren. Es ist in jedem Fall keine gute Idee, dass das Modell für die Aufrechterhaltung des Zustands des Viewmodels verantwortlich ist. Das ist das Problem des Viewmodels, lass ihn damit umgehen.

private void chooseNewLabel() 
{ 
    if (ScriptCollection.Count > 0) 
    { 
     ScriptCollection = P4LabelBatteryModel.TagsFilesModel(NewLabel, ScriptCollection); 
     ++FilesProcessedBlck; 
    } 
} 

Und im Modell ...

public static ObservableCollection<ScriptModel> TagsFilesModel(string NewLabel, IList<ScriptModel> scriptsToTagColl) 
{ 
    string newLabel = NewLabel; 
    string[] files = null; 

    // This will generate an IPC when returned 
    ObservableCollection<ScriptModel> newCollection = new ObservableCollection<ScriptModel>(); 

    //code here that modifies newCollection xaml updates when this returns, _p4LabelBatteryViewModel.FilesProcessedBlck++; does not. 

    return newCollection; 
} 

Ich habe ein paar andere kleinere Änderungen TagsFilesModel zu vereinfachen. Zum Beispiel gibt es keinen Grund dafür, dass Anrufer eine ObservableCollection<T> übergeben müssen. Sie haben vielleicht nie einen Grund, etwas anderes zu geben, aber wenn Sie sich diese Art von Flexibilität in Ihrem Code angewöhnen, zahlt sich das aus.

Ein weiterer Artikel. Dies ist harmlos, aber es lohnt sich zu wissen:

<TextBlock 
    x:Name="FilesProcessedBlck" 
    HorizontalAlignment="Left" 
    Margin="54,507,0,0" 
    TextWrapping="Wrap" 
    Text="{Binding FilesProcessedBlck}" 
    VerticalAlignment="Top" 
    RenderTransformOrigin="-0.7,0.562" 
    Width="65" 
    /> 

UpdateSourceTrigger=PropertyChanged dient nicht gegenstandslos in diesem Binding. Die "Quelle" einer Bindung ist die Viewmodel-Eigenschaft. Das "Ziel" ist die UI-Steuerelementeigenschaft. UpdateSourceTrigger=PropertyChanged teilt dem Binding mit, die viewmodel -Eigenschaft immer dann zu aktualisieren, wenn sich die Steuereigenschaft ändert. Das scheint albern, aber Sie können es auch auf UpdateSourceTrigger=LostFocus setzen; TextBox.Text ist standardmäßig LostFocus, weil der übliche Fall mit TextBox ist, dass der Benutzer für eine Weile eingibt, aber Sie wirklich nicht interessiert, Ihr Ansichtsmodell zu aktualisieren, bis er die Eingabe beendet und den Fokus auf ein anderes Steuerelement ändert.Das Aktualisieren einer viewmodel -Eigenschaft kann viele Nebeneffekte haben. Wenn Sie die Eigenschaft bound viewmodel jedes Mal aktualisieren, wenn sich die Text ändert, können Sie in einigen Fällen zu pathologischem Verhalten kommen: Jedes Mal, wenn der Benutzer einen Buchstaben eingibt, eine ganze Menge Code wird in Bewegung gebracht, so sehr, dass die Benutzeroberfläche abstürzt. So LostFocus.

Das ist alles Off-Thema für diese Frage, denn das ist kein TextBox. Es ist eine TextBlock, die die Quelleigenschaft überhaupt nicht aktualisieren kann, so dass Flag keine Wirkung hat.

Übrigens, was bedeutet "Blck"? Ist das, weil es in einem TextBlock angezeigt wird? Was passiert, wenn ein anderer Ort in der Benutzeroberfläche hinzugefügt wird, wo er angezeigt wird, aber der neue ist ein Label ;; sollten Sie es dann umbenennen ? Besser, es FilesProcessedCount zu nennen und das viewmodel aus dem Geschäft herauszuhalten, das sich kümmert, was die UI tut.

+0

Ed, Danke für die Hilfe. Die "Blck" ist Block, Holdover von Namenskonvention an einem Ort, an dem ich gearbeitet habe. Ich habe versucht, "Kein Code dahinter" zu verwenden, aber es vielleicht zu weit getragen. Im Modell habe ich eine Schleife, die zählt, wie viele Elemente verarbeitet werden, und ich habe versucht, das (FilesProcessedBlck) vom Modell zu aktualisieren, bevor ich zurück zum ViewModel gehe, anscheinend ist das schlecht zu machen. – coolercargo

Verwandte Themen