У меня проблема с привязкой данных в WPF. Задание, запущенное в конструкторе, отлично работает. Но когда я попытался запустить задачу в обработчике таймера, она не сработала -> данные на экране не обновились ...
public ObservableCollection<ushort> Test2{get; set;}
public Settings()
{
InitializeComponent();
Test2 = new ObservableCollection<ushort>();
Test2.Add(666);
Test2.Add(111);
Task.Run(async () =>
{
int i = 0;
while (true)
{
await Task.Delay(500);
Test2[1] += (ushort)2;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Test2)));
}
});
}
private void OnTimedEvent(Object source, System.Timers.ElapsedEventArgs e)
{
Task.Run(async () =>
{
int i = 0;
while (true)
{
await Task.Delay(500);
Test2[1] += (ushort)2;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Test2)));
}
});
}
Таймер
oTimer.Interval = 1000;
oTimer.Elapsed += OnTimedEvent;
oTimer.AutoReset = true;
oTimer.Enabled = true;
oTimer.Start();
Другой файл класса
public UserControlHome()
{
InitializeComponent();
DataContext = new Settings();
}
И файл XML
<TextBlock x:Name = "Tob2Sensor1" Grid.Column = "1" Text = "{Binding Test2[1]}" HorizontalAlignment = "Center"/>
Я добавил конфигурацию таймера. Но таймер работает хорошо.





Попробуйте удалить задачу из события таймера:
private void OnTimedEvent(Object source, System.Timers.ElapsedEventArgs e)
{
Test2[1] += (ushort)2;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Test)));
}
Я пробовал, не помогло ... Обновление данных в представлении работает только тогда, когда я нахожусь в конструкторе ...
Попробуйте завернуть его в Диспетчер
Application.Current.Dispatcher.Invoke(() => PropertyChanged(this, new PropertyChangedEventArgs(nameof(Test)));));
Обновлено: Это работает для меня (я использую последнюю версию Prism.Core от Nuget):
using Prism.Mvvm;
using System;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.Timers;
using System.Windows;
namespace ArrayBinding
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new Settings();
}
}
class Settings: BindableBase
{
public ObservableCollection<ushort> Test2 { get; set; }
private Timer oTimer = new Timer();
public Settings()
{
Test2 = new ObservableCollection<ushort>();
Test2.Add(666);
Test2.Add(111);
oTimer.Interval = 1000;
oTimer.Elapsed += OnTimedEvent;
oTimer.AutoReset = true;
oTimer.Enabled = true;
oTimer.Start();
}
private void OnTimedEvent(Object source, System.Timers.ElapsedEventArgs e)
{
Task.Run(async () =>
{
while (true)
{
await Task.Delay(500);
Test2[1] += (ushort)2;
}
});
}
}
}
Можете ли вы куда-нибудь загрузить свой проект, чтобы люди могли больше помогать?
Его работа с BindableBase, но я не могу наследовать от этого класса, потому что этот класс уже наследуется от другого класса
он работает, когда я запускаю таймер в конструкторе. Но когда я хочу запустить таймер после нажатия кнопки, он не работает ....
Вы имеете в виду код, унаследованный от BindableBase?
Да .. если вы можете протестировать с запуском таймера в кнопке, вы увидите
В версии конструктора вызывать PropertyChanged не нужно - поэтому он работает
В версии обратного вызова таймера ваша строка PropertyChanged неверна, попробуйте следующее:
PropertyChanged(this, new PropertyChangedEventArgs("Test2[1]"));
Может быть проблема с перекрестным потоком. WPF не позволяет изменять связанную коллекцию извне потока пользовательского интерфейса. Попробуйте следующее:
<!-- language: c# -->
private void OnTimedEvent(Object source, System.Timers.ElapsedEventArgs e)
{
Task.Run(async () =>
{
int i = 0;
while (true)
{
await Task.Delay(500);
Dispatcher.Invoke(()=>
{
Test2[1] += (ushort)2;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Test2)));
});
}
}
}
IMO часть async устарела. Вы можете сделать, как написал Ник, но внутри диспетчера invoke.
Я тоже попробовал решение Милослава, и оно сработало нормально.
Хорошо, я внес несколько изменений.
public Settings()
{
InitializeComponent();
Test2 = new ObservableCollection<ushort>();
Test2.Add(100);
Test2.Add(99);
Test2.Add(98);
dispatcherTimer.Tick += dispatcherTimer_Tick;
dispatcherTimer.Interval = new TimeSpan(0, 0, 1);
}
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
Task.Run(async () =>
{
int i = 0;
while (true)
{
await Task.Delay(500);
Dispatcher.Invoke(() =>
{
Test2[1] += (ushort)2;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Test2)));
});
}
});
}
public void Button_Click(object sender, RoutedEventArgs e)
{
dispatcherTimer.Start();
}
И это не работает. Но когда я запускаю таймер «dispatcherTimer.Start ();» в конструкторе все нормально ....
Какой таймер? Где вы это определили? Можете ли вы предоставить MCVE?