2017-09-13 7 views
0

Un exercice simple: affichez l'heure actuelle dans un bloc de texte dans une application UWP. J'utilise MVVMlight et PropertyChanged.Fody.L'application UWP ne met pas à jour la vue

En tant que base pour cet exemple que je utilise cet article Article 1 et la MVVMlight/mise en œuvre d'ici Fody: Article 2

J'ai un MainViewModel. Ici, je crée une instance de la classe DateTimeModel et j'ai déjà ajouté une sortie Debug si la propriété a changé l'événement est déclenché (travail).

using System.Diagnostics; 
 
using GalaSoft.MvvmLight; 
 
using Logic.Ui.Models.DateTime; 
 
using PropertyChanged; 
 

 
namespace Logic.Ui 
 
{ 
 
    public class MainViewModel : ViewModelBase, INotifyPropertyChanged 
 
    { 
 

 
     public DateTimeModel DateTimeModel; 
 

 
     [DependsOn(nameof(DateTimeModel))] 
 
     public DateTime CurrentDateTime => DateTimeModel.CurrentDateTime; 
 

 
     public MainViewModel() 
 
     { 
 
      DateTimeModel = new DateTimeModel(); 
 

 
      DateTimeModel.PropertyChanged += (s, e) => 
 
      { 
 
       Debug.WriteLine("DateTime PropertyChanged"); 
 
      }; 
 
     } 
 

 
     #region Events 
 

 
     public event PropertyChangedEventHandler PropertyChanged; 
 

 
     #endregion 
 

 
    } 
 
}

Et une classe DateTimeModel où je mets à jour l'heure à l'aide d'un ThreadPoolTimer:

using System; 
 
using System.ComponentModel; 
 
using System.Diagnostics; 
 
using Windows.System.Threading; 
 
using Windows.UI.Core; 
 

 
namespace Logic.Ui.Models.DateTime 
 
{ 
 

 
    public class DateTimeModel : INotifyPropertyChanged 
 
    { 
 
     private ThreadPoolTimer _clockTimer; 
 

 
     public System.DateTime CurrentDateTime { get; set; } 
 
     
 
     public DateTimeModel() 
 
     { 
 
      _clockTimer = ThreadPoolTimer.CreatePeriodicTimer(ClockTimerTickAsync, TimeSpan.FromMilliseconds(1000)); 
 
     } 
 

 
     private async void ClockTimerTickAsync(ThreadPoolTimer timer) 
 
     { 
 
      await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,() => 
 
      { 
 
       CurrentDateTime = System.DateTime.Now; 
 
       Debug.WriteLine("Time updated"); 
 
      }); 
 

 
     } 
 

 
     #region Events 
 

 
     public event PropertyChangedEventHandler PropertyChanged; 
 

 
     #endregion 
 
    } 
 
}

Le code XAML ressemble à ceci:

<Page 
 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
 
    xmlns:local="using:MirrorV2.Ui.Raspberry" 
 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
 
    x:Class="MirrorV2.Ui.Raspberry.MainPage" 
 
    mc:Ignorable="d" 
 
    DataContext="{Binding Main, Source={StaticResource Locator}}"> 
 

 
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> 
 

 
     <TextBlock Text="{Binding CurrentDateTime}"/> 
 
     
 
    </Grid> 
 
</Page>

Le problème ici est que l'interface est pas mis à jour, alors que les événements PropertyChanged sont beeing élevés. Qu'est-ce qui me manque ici?

EDIT: Si j'utilise CurrentDateTime comme une propriété standard:

public DateTime CurrentDateTime { get; set; } 

et l'affectation du DateTime courant dans le constructeur les travaux de liaison.

CurrentDateTime = System.DateTime.Now; 

Répondre

2

problème que vous êtes confronté est MainViewModel.CurrentDateTime n'est notifié lorsque vous attribuez MainViewModel.DateTimeModel, pas lorsque les propriétés de DateTimeModel changent.

This is a known Fody limitation et un gars here found a walkaround qui vous permet d'informer sur les changements de propriétés secondaires comme ceci:

public class MainViewModel : ViewModelBase, INotifyPropertyChanged 
{ 

    // ... snip ... 

    [DependsOn(nameof(DateTimeModel))] 
    [DependsOn("DateTimeModel.CurrentDateTime")] 
    public DateTime CurrentDateTime => DateTimeModel.CurrentDateTime; 
} 

Mais je pense qu'il est beaucoup plus élégant de laisser tomber le MainViewModel.CurrentDateTime et se lier à MainViewModel.DateTimeModel directement

<TextBlock Text="{Binding DateTimeModel.CurrentDateTime}"/> 

Cela nécessite de changer DateTimeModel en propriété comme suggéré par mm8:

public DateTimeModel DateTimeModel { get; } 
+0

J'ai utilisé la reliure directe - c'est la façon la plus élégante pour moi. Merci. – Christoph

1

Déclenchez l'événement PropertyChanged pour la CurrentDateTime du MainViewModel que vous liez à chaque fois que l'événement PropertyChanged du DateTimeModel est élevé:

public class MainViewModel : ViewModelBase, INotifyPropertyChanged 
{ 
    public DateTimeModel DateTimeModel; 

    [DependsOn(nameof(DateTimeModel))] 
    public DateTime CurrentDateTime => DateTimeModel.CurrentDateTime; 

    public MainViewModel() 
    { 
     DateTimeModel = new DateTimeModel(); 

     DateTimeModel.PropertyChanged += (s, e) => 
     { 
      Debug.WriteLine("DateTime PropertyChanged"); 
      this.RaisePropertyChanged(nameof(CurrentDateTime)); //<--- 
     }; 
    } 

    #region Events 
    public event PropertyChangedEventHandler PropertyChanged; 
    #endregion 
} 

Ou vous pourriez DateTimeModel une propriété dans la classe MainViewModel:

public DateTimeModel DateTimeModel { get; private set; } 

... et de lier directement au CurrentDateTime propriété du DateTimeModel:

<TextBlock Text="{Binding DateTimeModel.CurrentDateTime}"/>