DataGrid生成空行

时间:2014-11-04 04:35:45

标签: c# wpf multithreading datagrid

我有两个主题 - 让我们将它们命名为Calc线程和UI线程。在Calc线程内部,我刷新了一个ObservableCollection。我还有一个ObservableCollection的CollectionCHanged事件的处理程序。据我所知,处理程序在引发CollectionChanged事件的同一个线程中执行 - 所以这是在我的情况下刷新ObservableCollection的相同线程。因此,要刷新UI,我不能像在单线程应用程序中那样直接使用绑定 - 必须通过Dispatcher手动刷新UI。但是当我在UI中使用DataGrid时,我得到空行而不是任何数据,例如,当我使用ListBox时,会显示相应的数据:

数据网格情况向左,列表框情况向右

(列表框只是例如数据绑定和显示;我不希望数据显示在此列表框中,但是像数据网格一样(如果它按预期工作 - 不是在案例中)在图片上) - 列标题的表格)

enter image description here

好吧,我准备了代码,您可以复制并粘贴以重建问题:

C#

using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Threading;
using System.Windows;

namespace WpfApplication1
{
    public class MyClass
    {
        public int Integer { get; set; }
        public string Str { get; set; }
    }    

    public partial class MainWindow : Window
    {
        public ObservableCollection<MyClass> MyCollection { get; set; }

        public MainWindow()
        {
            InitializeComponent();    

            MyCollection = new ObservableCollection<MyClass>();
            MyCollection.CollectionChanged += MyCollection_CollectionChanged;

            Thread t = new Thread(new ThreadStart(() =>
                {
                    for (int i = 0; i < 10; i++)
                    {
                        MyCollection.Add(new MyClass() 
                        {
                            Integer = i, 
                            Str = "String" + i
                        });
                        Thread.Sleep(500);
                    }
                }));

            t.Start();
        }

        void MyCollection_CollectionChanged(
            object sender, 
            NotifyCollectionChangedEventArgs e)
        {
            Dispatcher.Invoke(
                () =>
                {
                    foreach (var item in e.NewItems)
                        dataGrid.Items.Add((MyClass)item);
                });
        }
    }
}

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">

  <Grid>

    <!--<ListBox Name="dataGrid">
      <ListBox.ItemTemplate>
        <DataTemplate>
          <StackPanel>
            <TextBlock Text="{Binding Path=Integer}" />
            <TextBlock Text="{Binding Path=Str}" />
          </StackPanel>
        </DataTemplate>
      </ListBox.ItemTemplate>
    </ListBox>-->

    <DataGrid Name="dataGrid">
      <DataGrid.ItemTemplate>
        <DataTemplate>
          <StackPanel>
            <TextBlock Text="{Binding Path=Integer}" />
            <TextBlock Text="{Binding Path=Str}" />
          </StackPanel>
        </DataTemplate>
      </DataGrid.ItemTemplate>
    </DataGrid>

  </Grid>
</Window>

1 个答案:

答案 0 :(得分:1)

这是你想要的吗?

C#

namespace WpfApplication1
{
    public class MyClass
    {
        public int Integer { get; set; }
        public string Str { get; set; }
    }

    public partial class MainWindow : Window
    {
        public ObservableCollection<MyClass> MyCollection { get; set; }

        public MainWindow()
        {
            InitializeComponent();
            DataContext = this;
            MyCollection = new ObservableCollection<MyClass>();

            Thread t = new Thread(new ThreadStart(() =>
            {
                for (int i = 0; i < 10; i++)
                {
                   Dispatcher.Invoke(new Action(() =>
                   {
                    MyCollection.Add(new MyClass()
                    {
                        Integer = i,
                        Str = "String " + i
                    });
                   }));
                }
            }));

            t.Start();
        }
    }
}

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">

    <Grid>
        <DataGrid Name="dataGrid" ItemsSource="{Binding MyCollection}">
            <DataGrid.ItemTemplate>
                <DataTemplate>
                    <StackPanel>
                        <TextBlock Text="{Binding Integer}" />
                        <TextBlock Text="{Binding Str}" />
                    </StackPanel>
                </DataTemplate>
            </DataGrid.ItemTemplate>
        </DataGrid>

    </Grid>
</Window>

其他方法是使用另一个List:

public partial class MainWindow : Window
    {
        private List<MyClass> _MyCollection;
        public ObservableCollection<MyClass> MyCollection { get; set; }

        private DispatcherTimer dispatcherTimer = new DispatcherTimer();

        public MainWindow()
        {
            InitializeComponent();
            DataContext = this;
            MyCollection = new ObservableCollection<MyClass>();
            _MyCollection = new List<MyClass>();
            dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 500);
            dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);

            Thread t = new Thread(new ThreadStart(() =>
            {
                for (int i = 0; i < 10; i++)
                {
                    _MyCollection.Add(new MyClass()
                    {
                        Integer = i,
                        Str = "String " + i
                    });
                    Thread.Sleep(500);
                }
            }));

            t.Start();
            dispatcherTimer.Start();
        }

        private void dispatcherTimer_Tick(object sender, EventArgs e)
        {
            if (_MyCollection.Count != MyCollection.Count)
            {
                MyCollection.Add(_MyCollection[_MyCollection.Count - 1]);
            }
        }
    }

第二次编辑你的例子:

namespace WpfApplication1
{
    public class MyClass
    {
        public int Integer { get; set; }
        public string Str { get; set; }
    }

    public partial class MainWindow : Window
    {
        private ObservableCollection<MyClass> _MyCollection;
        public ObservableCollection<MyClass> MyCollection { get; set; }

        public MainWindow()
        {
            InitializeComponent();
            DataContext = this;
            MyCollection = new ObservableCollection<MyClass>();
            _MyCollection = new ObservableCollection<MyClass>();
            _MyCollection.CollectionChanged += new NotifyCollectionChangedEventHandler(_MyCollection_CollectionChanged);

            Thread t = new Thread(new ThreadStart(() =>
            {
                for (int i = 0; i < 10; i++)
                {
                    _MyCollection.Add(new MyClass()
                    {
                        Integer = i,
                        Str = "String " + i
                    });
                    Thread.Sleep(500);
                }
            }));

            t.Start();
        }

        private void _MyCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            Dispatcher.Invoke(new Action(
                () =>
                {
                    foreach (var item in e.NewItems)
                        MyCollection.Add((MyClass)item);
                }));
        }
    }
}