Приложение UWP не обновляет представление
Простое упражнение: отображение текущего времени в текстовом блоке в приложении UWP. Я использую MVVMlight и PropertyChanged.Fody.
В качестве основы для этого примера я использую эту статью Article 1 и реализацию MVVMlight / Fody отсюда: Article 2
У меня есть MainViewModel. Здесь я создаю экземпляр класса DateTimeModel, и я уже добавил выходные данные отладки, если событие свойства изменено (работает).
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
}
}
И класс DateTimeModel, где я обновляю время, используя 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
}
}
Код XAML выглядит так:
<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>
Проблема здесь в том, что пользовательский интерфейс не обновляется, в то время как события propertyChanged возникают. Что мне здесь не хватает?
РЕДАКТИРОВАТЬ: Если я использую CurrentDateTime в качестве стандартного свойства:
public DateTime CurrentDateTime { get; set; }
и присвоение текущего DateTime в конструкторе, привязка работает.
CurrentDateTime = System.DateTime.Now;
2 ответа
Проблема, с которой вы столкнулись MainViewModel.CurrentDateTime
только получает уведомление, когда вы назначаете MainViewModel.DateTimeModel
не когда DateTimeModel
Свойства меняются.
Это известное ограничение Fody, и один парень здесь нашел обходной путь, который позволяет вам уведомлять об изменениях в свойствах, например:
public class MainViewModel : ViewModelBase, INotifyPropertyChanged
{
// ... snip ...
[DependsOn(nameof(DateTimeModel))]
[DependsOn("DateTimeModel.CurrentDateTime")]
public DateTime CurrentDateTime => DateTimeModel.CurrentDateTime;
}
Но я думаю, что гораздо элегантнее отбросить MainViewModel.CurrentDateTime
и привязать к MainViewModel.DateTimeModel
непосредственно
<TextBlock Text="{Binding DateTimeModel.CurrentDateTime}"/>
Это требует изменения DateTimeModel
к собственности, как предложено мм8:
public DateTimeModel DateTimeModel { get; }
Поднять PropertyChanged
событие для CurrentDateTime
из MainViewModel
что вы связываете всякий раз, когда PropertyChanged
событие DateTimeModel
Поднялся:
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
}
Или ты мог DateTimeModel
недвижимость в MainViewModel
учебный класс:
public DateTimeModel DateTimeModel { get; private set; }
... и привязать непосредственно к CurrentDateTime
собственность DateTimeModel
:
<TextBlock Text="{Binding DateTimeModel.CurrentDateTime}"/>