简体   繁体   English

WPF中的绑定数组

[英]Binding arrays in WPF

I have a problem with binding data in WPF. 我在WPF中绑定数据时遇到问题。 Task runed in constructor work perfect. 在构造函数中运行的任务工作完美。 But when i tried to run task in timer handler it didnt work -> the data in view didnt update... 但是当我尝试在计时器处理程序中运行任务时它没有起作用->视图中的数据没有更新...

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

Timer 计时器

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

Other class file 其他班级文件

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

And the XML file 和XML文件

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

Try removing the task from the timer event: 尝试从计时器事件中删除任务:

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

Try wrap it up inside a Dispatcher 尝试将其包装在分派器中

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

EDIT: This works for me (I'm using latest Prism.Core from Nuget): 编辑:这对我有效(我正在使用Nuget的最新Prism.Core):

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

In the constructor version you don't need to call PropertyChanged - which is why it works 在构造函数版本中,您无需调用PropertyChanged这就是它起作用的原因

In the timer callback version, your PropertyChanged line is incorrect, try this: 在计时器回调版本中,您的PropertyChanged行不正确,请尝试以下操作:

PropertyChanged(this, new PropertyChangedEventArgs("Test2[1]"));

Might be a cross-threading problem. 可能是跨线程问题。 WPF does not allow changing bound collection from outside the UI thread. WPF不允许从UI线程外部更改绑定集合。 Try the following: 请尝试以下操作:

<!-- 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 the 'async' part is obsolete. IMO的“异步”部分已过时。 You can do as Nick has written, but inside the dispatcher invoke. 您可以像Nick所写的那样做,但是在调度程序内部调用。

Ok, i made few changes. 好的,我做了几处更改。

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

And it doesnt work. 而且它不起作用。 But when I run timer "dispatcherTimer.Start();" 但是当我运行计时器“ dispatcherTimer.Start();”时 in constructor everythink is ok.... 在构造函数中,一切都可以。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM