DataGrid生成空行 [英] DataGrid generates empty rows
问题描述
数据网格左边的情况,右边的列表框案例
(列表框只是例如数据绑定和显示;我不希望显示数据像在这个列表框中,但像数据网格(如果它按照我的预期工作 - 不如图片中的情况) - 表的列标题)
嗯,我准备好了代码,您可以复制并粘贴以重建问题:
C#
使用System.Collections.ObjectModel;
使用System.Collections.Specialized;
使用System.Threading;
使用System.Windows;
命名空间WpfApplication1
{
public class MyClass
{
public int Integer {get;组; }
public string Str {get;组; }
}
public partial class MainWindow:Window
{
public ObservableCollection< MyClass> MyCollection {get;组; }
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(
对象发件人,
NotifyCollectionChangedEventArgs e)
{
Dispatcher.Invoke(
()= >
{
foreach(e.NewItems中的var item)
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 =MainWindowHeight =350Width =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>
这是你想要的吗?
C#
命名空间WpfApplication1
{
public class MyClass
{
public int Integer {get;组; }
public string Str {get;组; }
}
public partial class MainWindow:Window
{
public ObservableCollection< MyClass> MyCollection {get;组; }
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 =MainWindowHeight =350Width = 525>
< Grid>
< DataGrid Name =dataGridItemsSource ={Binding MyCollection}>
< DataGrid.ItemTemplate>
< DataTemplate>
< StackPanel>
< TextBlock Text ={Binding Integer}/>
< TextBlock Text ={Binding Str}/>
< / StackPanel>
< / DataTemplate>
< /DataGrid.ItemTemplate>
< / DataGrid>
< / Grid>
< / Window>
其他方法是使用另一个列表:
public partial class MainWindow:Window
{
private List< MyClass> _我的收藏;
public ObservableCollection< MyClass> MyCollection {get;组; }
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]);
}
}
}
第二次编辑与你的例子:
命名空间WpfApplication1
{
public class MyClass
{
public int Integer {get;组; }
public string Str {get;组; }
}
public partial class MainWindow:Window
{
private ObservableCollection< MyClass> _我的收藏;
public ObservableCollection< MyClass> MyCollection {get;组; }
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(e.NewItems中的var item)
MyCollection.Add((MyClass)项);
}));
}
}
}
I have two threads - let's name them Calc thread and UI thread. Inside the Calc thread I refreshes an ObservableCollection. I also have a handler for the CollectionCHanged event of the ObservableCollection. As I know, the handler executes within the same thread that raises the CollectionChanged event - so that is the same thread that refreshes the ObservableCollection in my case. So, to refresh UI I can't use bindings directly as in single-threaded application - UI must be refreshed manually through Dispatcher. But when I use DataGrid in the UI I get the empty rows instead of any data, and when I use ListBox, for example, the appropriate data is showed:
data grid case to the left, list box case to the right
(list box is just for example that the data binds and shows; I don't want the data to be showed like in this list box, but like in data grid (if it worked as I expect - not as in case on the picture) - table with column titles)
Well, I prepared the code, which you can copy and paste to reconstruct the problem:
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 (just comment/uncomment the list box case and the data grid case):
<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>
Is this what you want?
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>
Other method is to use another 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]);
}
}
}
Second edit with you example:
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);
}));
}
}
}
这篇关于DataGrid生成空行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!