0
votes

Liaison de tableaux dans WPF

J'ai un problème avec la liaison des données dans WPF. La tâche exécutée dans le constructeur fonctionne parfaitement. Mais quand j'ai essayé d'exécuter la tâche dans le gestionnaire de minuterie, cela n'a pas fonctionné -> les données affichées ne se sont pas mises à jour ...

<TextBlock x:Name="Tob2Sensor1" Grid.Column="1" Text="{Binding Test2[1]}" HorizontalAlignment="Center"/>

Minuterie

public UserControlHome()
    { 
        InitializeComponent();
       DataContext = new Settings();
    }

Autre fichier de classe

oTimer.Interval = 1000;               
oTimer.Elapsed += OnTimedEvent;
oTimer.AutoReset = true;
oTimer.Enabled = true;
oTimer.Start();             

Et le fichier XML

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


2 commentaires

Quelle minuterie? Où l'avez-vous défini? Pouvez-vous fournir un MCVE ?


J'ai ajouté la configuration de la minuterie. Mais, la minuterie fonctionne bien.


5 Réponses :


0
votes

Essayez de supprimer la tâche de l'événement du minuteur:

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


1 commentaires

J'ai essayé, je n'ai pas aidé ... La mise à jour des données en vue ne fonctionne que lorsque je suis dans le constructeur ...



0
votes

Essayez de l'envelopper dans un Dispatcher

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

MODIFIER: Cela fonctionne pour moi (j'utilise le dernier Prism.Core de Nuget):

Application.Current.Dispatcher.Invoke(() => PropertyChanged(this, new PropertyChangedEventArgs(nameof(Test)));));


5 commentaires

Pouvez-vous télécharger votre projet quelque part pour que les gens puissent vous aider davantage?


Il fonctionne avec BindableBase, mais je ne peux pas hériter de cette classe car cette classe hérite déjà d'une autre classe


cela fonctionne quand je lance la minuterie dans le constructeur. Mais quand je veux exécuter la minuterie après un clic sur le bouton, cela ne fonctionne pas ....


Voulez-vous dire le code qui hérite de BindableBase?


Oui .. si vous pouviez tester avec le bouton de démarrage de la minuterie, vous verrez



0
votes

Dans la version du constructeur, vous n'avez pas besoin d'appeler Propertychanged - C'est pourquoi il fonctionne

dans la version de rappel de la minuterie, votre La ligne de propriété est incorrecte, Essayez ceci: xxx


0 commentaires

0
votes

Peut-être un problème de filetage croisé. WPF n'autorise pas la modification de la collection liée depuis l'extérieur du thread d'interface utilisateur. Essayez ce qui suit:

<!-- 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, la partie 'async' est obsolète. Vous pouvez faire ce que Nick a écrit, mais à l'intérieur du répartiteur, invoquez.


1 commentaires

J'ai également essayé la solution de Miłosław et cela a bien fonctionné.



0
votes

D'accord, j'ai apporté quelques modifications.

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

Et cela ne fonctionne pas. Mais quand j'exécute la minuterie "dispatcherTimer.Start ();" dans le constructeur, tout est ok ....


0 commentaires