【问题标题】:Binding Collection to ListBox [duplicate]将集合绑定到 ListBox [重复]
【发布时间】:2017-05-04 16:37:29
【问题描述】:

我尝试做一些简单的任务(我猜是这样)。我想从 for 循环中动态更改 GUI。
让我们看看我的 XAML:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel Name="MyPanel">
        <TextBlock Text="{Binding MyValue}"></TextBlock>
        <Button Click="Button_Click">OK</Button>
        <ListBox Name="myList" ItemsSource="{Binding MyCollection}" >
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Grid Margin="10">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="20"/>
                            <ColumnDefinition Width="20"/>
                        </Grid.ColumnDefinitions>
                        <TextBlock Text="{Binding A}" Grid.Column="0"/>
                        <TextBlock Text="{Binding B}" Grid.Column="1"/>
                    </Grid>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </StackPanel>
</Window>

如您所见,我有显示数字的文本块、启动程序的按钮和应该显示集合项的列表框。

单击按钮后,第一个文本块(绑定 MyValue)显示动态值,但在列表框上出现下一个错误:
“这种类型的 CollectionView 不支持从不同于 Dispatcher 线程的线程更改其 SourceCollection。”
我看到了该错误的另一个答案,但无法理解如何在我的情况下实现它。

这里是 C# 代码:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public static MyModel m;
        public MainWindow()
        {
            m = new MyModel();
            InitializeComponent();
            MyPanel.DataContext = m;
        }

        bool flag = false;
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            flag = !flag;
            Task.Factory.StartNew(() =>
            {
                for (int i = 0; i < 5000000; i++)
                {
                    if (flag == false) break;
                    m.MyValue = i.ToString();
                    m.MyCollection.Add(new ChartPoint { A = i, B = 2 * i });
                }
            });
        }
    }

    public class MyModel : INotifyPropertyChanged
    {
        private string myValue;


        public ObservableCollection<ChartPoint> MyCollection { get; set; }

        public MyModel()
        {
            MyCollection = new ObservableCollection<ChartPoint>();
        }

        public string MyValue
        {
            get { return myValue; }
            set
            {
                myValue = value;
                RaisePropertyChanged("MyValue");
            }
        }

        private void RaisePropertyChanged(string propName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
        public event PropertyChangedEventHandler PropertyChanged;
    }

    public class ChartPoint
    {
        public int A { get; set; }
        public int B { get; set; }
    }
}

非常感谢!

【问题讨论】:

  • 如果您的程序在 .NET 4.5 或更高版本上运行,那么只要您想在其他(后台)线程中更改您的集合,就无需处理 Dispatcher.Invoke/Dispatcher.BeginInvoke。只需在BindingOperations.EnableCollectionSynchronization 的帮助下指示 WPF 绑定引擎允许 Dispatcher 以外的其他线程更改您的 ObservableCollection。详情见this answer to a related question

标签: c# wpf xaml data-binding


【解决方案1】:

Button_Click的代码我稍微改了一下,是不是你想实现的,请指教:

private void Button_Click(object sender, RoutedEventArgs e)
    {
      flag = !flag;

      var list = new List <ChartPoint>();

      Task.Factory.StartNew(() =>
      {
        for (int i = 0; i < 50000000; i++)
        {
          if (flag == false) break;
          m.MyValue = i.ToString();
          Dispatcher.BeginInvoke(new Action(() =>
                                            {
                                              m.MyCollection.Add(new ChartPoint
                                                                 {
                                                                   A = i,
                                                                   B = 2 * i
                                                                 });
                                            }),
                                 DispatcherPriority.Background);
        }
      });
    }

【讨论】:

  • 太棒了!!!你能解释一下吗?我在哪里可以读到它?
猜你喜欢
  • 2015-01-16
  • 1970-01-01
  • 2014-05-03
  • 2015-09-01
  • 2018-02-22
  • 2011-07-10
  • 2011-02-10
  • 1970-01-01
  • 2011-12-03
相关资源
最近更新 更多