Связывание массивов в WPF

У меня проблема с привязкой данных в 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"/>

Какой таймер? Где вы это определили? Можете ли вы предоставить MCVE?

Rekshino 04.01.2019 13:56

Я добавил конфигурацию таймера. Но таймер работает хорошо.

r00ti 04.01.2019 14:05
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
251
5

Ответы 5

Попробуйте удалить задачу из события таймера:

private void OnTimedEvent(Object source, System.Timers.ElapsedEventArgs e)
{
    Test2[1] += (ushort)2;
    PropertyChanged(this, new PropertyChangedEventArgs(nameof(Test)));
}

Я пробовал, не помогло ... Обновление данных в представлении работает только тогда, когда я нахожусь в конструкторе ...

r00ti 04.01.2019 13:54

Попробуйте завернуть его в Диспетчер

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;
        }
      });
    }
  }
}

Можете ли вы куда-нибудь загрузить свой проект, чтобы люди могли больше помогать?

Chinh Nguyen 05.01.2019 13:10

Его работа с BindableBase, но я не могу наследовать от этого класса, потому что этот класс уже наследуется от другого класса

r00ti 05.01.2019 22:28

он работает, когда я запускаю таймер в конструкторе. Но когда я хочу запустить таймер после нажатия кнопки, он не работает ....

r00ti 07.01.2019 11:43

Вы имеете в виду код, унаследованный от BindableBase?

Chinh Nguyen 09.01.2019 08:48

Да .. если вы можете протестировать с запуском таймера в кнопке, вы увидите

r00ti 09.01.2019 08:54

В версии конструктора вызывать 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.

Я тоже попробовал решение Милослава, и оно сработало нормально.

Klaus Gütter 04.01.2019 15:11

Хорошо, я внес несколько изменений.

    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 ();» в конструкторе все нормально ....

Другие вопросы по теме