2016-06-01 8 views
0

Ich versuche, mit einer UWP-App zu beginnen, obwohl ich komplett neu in xaml und C# bin. Dieses Problem hat mich jetzt mehrere Stunden gekostet. Ich habe schon viele Tutorials gesehen und die Antworten zu ähnlichen Fragen hier auf Stackoverflow gelesen, aber bisher hat noch nichts für mich funktioniert.Xaml-Ansicht wird nicht aktualisiert, während Objekte in beobachtbarer Sammlung aktualisiert werden

Ich habe eine ListView, die eine Datenbindung zu einer ObservableCollection hat. Es zeigt die Objekte in dieser Sammlung korrekt an, wenn ich die App starte. Wenn ich der Sammlung neue Objekte hinzufüge oder vorhandene Objekte lösche, wird das ListView korrekt aktualisiert. Aber wenn ich Objekte ändere, wird es nicht aktualisiert, obwohl ich INotifyPropertyChanged implementiere und das Ereignis auslöst, wenn sich eine Eigenschaft ändert.

Hier ist der Code:

Ansicht XAML

<Page 
x:Class="Prophecy_Challenge_Tracker.MainPage" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:local="using:Prophecy_Challenge_Tracker" 
xmlns:data="using:Prophecy_Challenge_Tracker.persistence" 
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
mc:Ignorable="d"> 

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> 
    <StackPanel x:Name="firstStack" Margin="8 ,32 ,0, 0 " Width="350" > 
     <ListView ItemsSource="{x:Bind ViewModel.Collection}" VerticalAlignment="Center" Background="Yellow" CanReorderItems="True"> 
      <ListView.ItemContainerStyle> 
       <Style TargetType="ListViewItem"> 
        <Setter Property="HorizontalContentAlignment" Value="Stretch" /> 
       </Style> 
      </ListView.ItemContainerStyle> 
      <ListView.ItemTemplate> 
       <DataTemplate x:DataType="data:Challenge" > 
        <Grid Background="Green" > 
         <Grid.ColumnDefinitions> 
          <ColumnDefinition Width="Auto"/> 
          <ColumnDefinition Width="*"/> 
          <ColumnDefinition Width="50"/> 
          <ColumnDefinition Width="Auto"/> 
         </Grid.ColumnDefinitions> 
         <Button Content="+" Grid.Column="0"/> 
         <TextBlock Grid.Column="1" Text="{x:Bind ChallengeName}" VerticalAlignment="Center"/> 
         <TextBlock Grid.Column="2" Text="{x:Bind Progress}" VerticalAlignment="Center" HorizontalAlignment="Center" /> 
         <Button Grid.Column="3" Content="X" /> 
        </Grid> 
       </DataTemplate> 
      </ListView.ItemTemplate> 
     </ListView> 
     <Button Content="Add" Click="add"/> 
     <Button Content="Delete" Click="delete"/> 
     <Button Content="Update Progress" Click="updateProgress"/> 
    </StackPanel> 
</Grid> 

Code hinter

using Prophecy_Challenge_Tracker.persistence; 
using Prophecy_Challenge_Tracker.viewmodel; 
using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.IO; 
using System.Linq; 
using System.Runtime.InteropServices.WindowsRuntime; 
using Windows.Foundation; 
using Windows.Foundation.Collections; 
using Windows.UI.Xaml; 
using Windows.UI.Xaml.Controls; 
using Windows.UI.Xaml.Controls.Primitives; 
using Windows.UI.Xaml.Data; 
using Windows.UI.Xaml.Input; 
using Windows.UI.Xaml.Media; 
using Windows.UI.Xaml.Navigation; 

namespace Prophecy_Challenge_Tracker 
{ 
    /// <summary> 
    /// Eine leere Seite, die eigenständig verwendet oder zu der innerhalb eines Rahmens navigiert werden kann. 
    /// </summary> 
    public sealed partial class MainPage : Page 
    { 

     public MainPage() 
     { 
      this.ViewModel = new Viewmodel(); 
      this.InitializeComponent(); 
      this.DataContext = ViewModel; 
     } 

     public Viewmodel ViewModel { get; set; } 

     int counter = 2; 
     private void add(object sender, RoutedEventArgs e) 
     { 
      counter++; 
      var c = new Challenge(); 
      c.ChallengeName = "Additional Line"; 
      c.Progress = counter + "/7"; 
      ViewModel.Collection.Add(c); 
     } 

     private void delete(object sender, RoutedEventArgs e) 
     { 
     var c = ViewModel.Collection.ElementAt(ViewModel.Collection.Count - 1); 
      ViewModel.Collection.Remove(c); 
      counter--; 
     } 

     private void updateProgress(object sender, RoutedEventArgs e) 
     { 
      var c = ViewModel.Collection.ElementAt(ViewModel.Collection.Count - 1); 
      int index = ViewModel.Collection.IndexOf(c); 
      counter++; 
      Debug.WriteLine("CurrentName: " + c.Progress); 
      c.Progress = counter + "/7"; 
      Debug.WriteLine("New Name: " + c.Progress); 
     } 
    } 
} 

Objektklasse

using System.ComponentModel; 
using System.Runtime.CompilerServices; 

namespace Prophecy_Challenge_Tracker.persistence 
{ 
    public class Challenge : INotifyPropertyChanged 
    { 
     private string challengeName; 
     public string ChallengeName 
     { 
      get { return challengeName; } 
      set 
      { 
       if (value != challengeName) 
       { 
        challengeName = value; 
        NotifyPropertyChanged("ChallengeName"); 
       } 
      } 
     } 

     private string progress = ""; 
     public string Progress 
     { 
      get { return progress; } 
      set 
      { 
       if (value != progress) 
       { 
        progress = value; 
        NotifyPropertyChanged("Progress"); 
       } 
      } 
     } 

     public event PropertyChangedEventHandler PropertyChanged; 
     public void NotifyPropertyChanged([CallerMemberName]string propertyName = "") 
     { 
      System.Diagnostics.Debug.WriteLine("Shortly before update. PropertyName = " + propertyName); 
      if (PropertyChanged != null) 
      { 
       System.Diagnostics.Debug.WriteLine("Update now"); 
       PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
      } 
     } 
    } 
} 

Ansichtsmodell

using Prophecy_Challenge_Tracker.persistence; 
using System; 
using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.ComponentModel; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 

namespace Prophecy_Challenge_Tracker.viewmodel 
{ 
    public class Viewmodel 
    { 

     public ObservableCollection<Challenge> Collection { get; set; } 

     public Viewmodel() 
     { 
      System.Diagnostics.Debug.WriteLine("New Viewmodel is being created"); 
      Collection = new ObservableCollection<Challenge>(); 
      Challenge c = new Challenge(); 
      c.ChallengeName = "First Line"; 
      c.Progress = "1/5"; 
      Collection.Add(c); 
      c = new Challenge(); 
      c.ChallengeName = "Second Line"; 
      c.Progress = "2/5"; 
      Collection.Add(c); 
     } 
    } 
} 

Antwort

4

Zusammengestellt Bindungen Standard OneTime, so dass sie nur am Anfang und nicht hören auf Änderungen einstellen.

Ändern Sie es an:

<ListView ItemsSource="{x:Bind ViewModel.Collection, Mode=OneWay}">... 

einen guten Überblick finden in this Build session auf Compiled Bindungen.

+0

Vielen Dank. Ich musste jedem Binding "Mode = OneWay" hinzufügen. Jetzt funktioniert es. Ich habe noch nie jemanden das erwähnen hören. Ich denke, das liegt daran, dass kompilierte Bindungen ziemlich neu sind. –

+2

Eigentlich, wenn Sie die Build-Videos darüber sehen, verbringen sie viel Zeit mit dieser speziellen Änderung. Das nächste, was Sie wahrscheinlich wundern wird, ist, dass kompilierte Bindungen keine geerbten Schnittstellen erkennen. Wenn Sie beispielsweise ein Basis-ViewModel haben, das INotifyProperty implementiert, müssen Sie die Schnittstelle explizit zu jedem abgeleiteten Typ hinzufügen, damit kompilierte Bindungen funktionieren. –

+0

@Kai, könnten Sie bitte den URI des Videos posten, in dem diese verbindliche Änderung erläutert wird. Klingt, als gäbe es beim Übergang von WPF zu UWP eine Reihe von Problemen. –