Я столкнулся с проблемой на днях. Я узнал, почему это происходит, но я никогда не сталкивался с такой проблемой, поэтому я не знаю, как ее решить.
У меня есть приложение, в котором в DashboardView (основном представлении) DispatcherTimer запускается в DashboardViewModel. Когда таймер тикает, мы получаем данные из базы данных, этот список привязан к данным между View и ViewModel. При появлении новых данных, вызвавших изменение базы данных, будет воспроизводиться звук.
Пользователь может перейти к другим представлениям. Когда пользователь возвращается к DashboardView, снова создается DashboardViewModel и DispatcherTimer.
Теперь есть 2 таймера, и они оба запускают событие Tick, создавая запутанный сценарий для пользователя.
Мое наблюдение за тем, что происходит в приложении прямо сейчас:
Мой таймер тикает каждую минуту. Когда я запускаю приложение, открывается DashboardView #1. Запускается DashboardViewModel #1, а также DispatcherTimer #1.
Я переключаюсь на другое представление и обновляю данные (новый адрес электронной почты), поэтому, когда таймер тикает, список в DashboardView изменится, и появится звук. воспроизводится.
Когда таймер №1 достигает 30 секунд, я переключаюсь на вновь созданный DashboardView, таким образом создавая View&ViewModel&Timer №2. Через 1 минуту срабатывает Таймер №1, появляются новые данные, поэтому он обновляет БД и воспроизводит звук, но список в представлении не обновляется. Я думаю, это потому, что вид № 2 отображается поверх № 1. Я знаю, потому что в противном случае я бы увидел наложение, говорящее об обновлении.
Представление № 2 привязано к данным ViewModel № 2. Таймер № 1 обновил ViewModel № 1, поэтому изменения не будут отображаться, поскольку мы не можем видеть представление № 1, поскольку оно заменено/перекрывается представлением № 2. Через 1 мин 30 секунд Таймер №2 тикает, получает данные из БД, не воспроизводит звук, так как БД уже была обновлена Таймером №1, и показывает данные в новом состоянии.< br> (надеюсь, это имело смысл)
Итак, TLDR: работает 2 таймера, хотя должен быть активен только 1 (думаю, самый новый). Как этого добиться?
Вот (часть) DashboardViewModel, как она у меня есть сейчас:
namespace QRM.ViewModel
{
class DashboardListViewModel : INotifyPropertyChanged
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
DBServer dbServer = new DBServer();
#region Constructor
public DashboardListViewModel()
{
log.Info("Dashboard Initializing - Starting...");
MyObservableCollection<View_server> listDashboard = new MyObservableCollection<View_server>();
ListDashboard = dbServer.ReadDashboard();
listBoxCommand = new RelayCommand(() => SelectionHasChanged());
// Refresh to get all new emails, errors, etc.
GetListDashboard();
IsRefreshing = Visibility.Collapsed;
// Make a timer to renew the data in the Dashboard automatically.
DispatcherTimer timer = new DispatcherTimer();
timer.Tick += new EventHandler(timer_Tick);
timer.Interval = Properties.Settings.Default.Timer_interval; // hours, minutes, seconds.
timer.Start();
//Receive the Notification sent after DashboardDetailsViewModel has handled the button commands, and call a respond method for the List.
App.Messenger.Register("RefreshServers", (Action)(() => GetListDashboard()));
App.Messenger.Register("ClearSelection", (Action)(() => SelectedServer = null));
App.Messenger.Register("ErrorSolved", (Action)(() => KeepSelection(selectedServer)));
App.Messenger.Register("WarningSound", (Action)(() => HasNewError = true));
log.Info("Dashboard Initializing - Done.");
}
#endregion
#region Get list dashboard
private void GetListDashboard()
{
HasNewError = false;
log.Info("Dashboard - Checking for Email...");
// The old Outlook class and methods
//EmailManager checkMail = new EmailManager();
//checkMail.GetEmail();
// First, check for mail.
IMAPManager checkMail = new IMAPManager();
checkMail.GetEmail();
log.Info("Dashboard - Checking for linked Errors...");
// Check if the emails have Errors linked to them. If not, add the Error from the Email to the DB
ErrorManager checkError = new ErrorManager();
checkError.GetNewErrors();
log.Info("Dashboard List - Starting...");
// Load the dashboard.
ListDashboard = dbServer.ReadDashboard();
System.Diagnostics.Debug.WriteLine("REFRESHED THE DASHBOARD");
log.Info("Dashboard List - Done.");
}
private void KeepSelection(View_server keepSelection)
{
GetListDashboard();
SelectedServer = keepSelection;
SelectionHasChanged();
}
#endregion
#region Timer
//This method runs every time the timer ticks.
private async void timer_Tick(object sender, EventArgs e)
{
log.Info("Dashboard - Refreshing...");
System.Diagnostics.Debug.WriteLine(">>Timer tick");
IsRefreshing = Visibility.Visible;
// To make sure the overlay is visible to the user, let it be on screen for at least a second (2x half a second)
await Task.Delay(500);
if (selectedServer != null)
{
KeepSelection(selectedServer);
}
else
{
GetListDashboard();
}
// 2nd half second.
await Task.Delay(500);
IsRefreshing = Visibility.Collapsed;
if (hasNewError == true)
{
System.Diagnostics.Debug.WriteLine("List has new error");
PlayWarningSound();
HasNewError = false;
}
else
{
System.Diagnostics.Debug.WriteLine("List has no new error");
HasNewError = false;
}
System.Diagnostics.Debug.WriteLine(">>End timer");
log.Info("Dashboard - Refreshed.");
}
#endregion
}
}
IDisposable
и, конечно же, вызывая его методDispose()
, где вы останавливаете таймер. - person Clemens   schedule 26.04.2016